本篇將主要講解游戲界面的構建和設計,會應用到egret.eui的自定義組件,可以很直觀的構建一個游戲整體,這里我們仍然只需要使用EgretWing就可以達到目的,本篇可能是篇幅最少的一個,但是涉及自定義組件和類繼承,希望能夠讀者能夠看明白,這對將來的游戲開發的思維幫助非常大。
自定義控件布局
首先先創建一個名為SceneGameSkin的exml皮膚,直接在這里面拖拖拽拽拼出初步的界面:
上面是題目區,下面是回答區,此時,找了了一下資源,發現字的方塊沒有放進資源文件,沒關系,我們可以直接使用eui.Rect這個基本空間創造一個字塊出來,exml描述如下:
<e:Rect ellipseWidth="20" fillColor="0xFFFFFF" strokeColor="0x0276D0" strokeWeight="4" ellipseHeight="20" right="0" left="0" bottom="0" top="0"/>
看看是不是和圖片上的很像,在編輯器里的基本面板屬性中是沒有ellipseWidth、ellipseHeight等等這些屬性的,需要點屬性欄右上角的所有屬性標簽才能顯示,然后微調即可。
可是,只有這個字塊背景是沒用的,還需要增加Label來顯示文字,但如果一個一個的匹配就很麻煩了,能不能使用skin來自己做一個自定組件自己管理並處理邏輯呢?這個很簡單,先構造一個skin然后配上一個自定義組件的代碼就可以實現了。
新建一個基於eui.Component的皮膚,大小設置為80x80:
<?xml version='1.0' encoding='utf-8'?> <e:Skin class="WordSkin" width="80" height="80" xmlns:e="http://ns.egret.com/eui" xmlns:w="http://ns.egret.com/wing"> <e:Rect ellipseWidth="20" fillColor="0xFFFFFF" strokeColor="0x0276D0" strokeWeight="4" ellipseHeight="20" right="0" left="0" bottom="0" top="0"/> <e:Label id="lb_text" text="字" horizontalCenter="0" verticalCenter="0" textColor="0x000000" size="60"/> </e:Skin>
新建一個typescript類,這里的名字就叫Word,繼承自eui.Component,處理代碼如下:
//普通的一個字,用來做問題的字塊使用 class Word extends eui.Component { protected lb_text:eui.Label; public constructor() { super(); this.addEventListener(egret.TouchEvent.TOUCH_TAP,this.onclick_tap,this); } protected onclick_tap(){ console.log(this.lb_text.text); } //這里沒有做成屬性的原因是因為當應用到eui的時候,Skin還未指定,運行時候會出現報錯,如果指定了SkinName,那么就會產生兩次eui的構建浪費內存 public setWordText(value:string){ this.lb_text.text = value; } public getWordText():string{ return this.lb_text.text; } }
保存編譯一下,然后在UI設計器的組件里就能看到一個Word自定義組件,然后將它拖進SceneGameSkin里,奇怪,怎么什么都沒有呢,因為還沒有指定皮膚:
指定好皮膚后,就會顯示正確了,下面開始進行布局操作,拖放擺好Group到SceneGameSkin的界面中,這里就可以用上Group的布局特性,比如下面的回答字里一共是20個漢字,可以使用Tile的方式排列成一個有序的陣列:
同樣上面的問題欄中,可以使用Group的橫向排列,調整你的界面直到滿意。
繼承的方式擴展自定義組件
那么好了,自此基本上已經完成,一般來說,后面就可以完全靠代碼控制來實現字塊的顯示和處理了,但這還不夠,因為下面的字和上面的字雖然樣子一樣,但處理的邏輯不一樣,比如說,下面的字是一點就自己消失,同時將文本放置到上面的答案中,而上面的字點擊就會移除自己的文本顯示,同時將下面的對應字塊顯示出來,如果用比較笨的方法,就是在代碼中加一個字典對應起來,然后增加一大堆,看起來很繞圈的代碼,其實這里的游戲邏輯很簡單,一個答案字只會對應一個回答字,如果在組件上帶上回答字塊的對象,不就好處理了嗎?如果每個Word控件都增加一個變量保存選定太顯得暴力,這里可以使用繼承增加一個SelectWord變量,而其他的邏輯可以通過重載方法來保持代碼的簡潔性,下面就是實現了一個繼承自Word的AnswerWord類,這個類同樣在保存編譯后,也會出現在自定義組件中,
//繼承自“問題字”,“答案字”是放在上面回答區域, //由於當答案字點擊的時候,答案字會消失並將對應的問題字還原顯示 class AnswerWord extends Word{ public SelectWord:Word = null; public constructor() { super(); } protected onclick_tap() { if(this.SelectWord != null){ this.SelectWord.visible = true; this.SelectWord = null; this.setWordText(""); } console.log("AnswerWord"); } //當一個問題字被選擇添加到回答的時,設置不可見,並保存到本對象中以后使用 public SetSelectWord(word:Word){ word.visible = false; this.setWordText(word.getWordText()); this.SelectWord = word; } }
那么我們將上面的四個漢字都給替換成AnswerWord,點擊一下試試看看命令欄里的輸出,不明白的可以參看上面的注釋。
最終的SceneGameSkin.exml代碼如下:

<?xml version='1.0' encoding='utf-8'?> <e:Skin class="SceneGameSkin" width="720" height="1136" xmlns:e="http://ns.egret.com/eui" xmlns:w="http://ns.egret.com/wing" xmlns:ns1="*"> <e:Image source="GameBG3_jpg" left="0" top="0" bottom="0" right="0"/> <e:Image source="WordFrame_png" x="39" y="120"/> <e:Group id="group_words" width="538" height="417" x="108" y="637"> <ns1:Word x="80" y="106" skinName="WordSkin"/> <ns1:Word skinName="WordSkin" y="116" x="90"/> <ns1:Word skinName="WordSkin" y="126" x="100"/> <ns1:Word skinName="WordSkin" y="136" x="110"/> <ns1:Word skinName="WordSkin" y="146" x="120"/> <ns1:Word skinName="WordSkin" y="156" x="130"/> <ns1:Word skinName="WordSkin" y="166" x="140"/> <ns1:Word skinName="WordSkin" y="176" x="150"/> <ns1:Word skinName="WordSkin" y="186" x="160"/> <ns1:Word skinName="WordSkin" y="196" x="170"/> <ns1:Word skinName="WordSkin" y="206" x="180"/> <ns1:Word skinName="WordSkin" y="216" x="190"/> <ns1:Word skinName="WordSkin" y="226" x="200"/> <ns1:Word skinName="WordSkin" y="236" x="210"/> <ns1:Word skinName="WordSkin" y="246" x="220"/> <ns1:Word skinName="WordSkin" y="256" x="230"/> <ns1:Word skinName="WordSkin" y="266" x="240"/> <ns1:Word skinName="WordSkin" y="276" x="250"/> <ns1:Word skinName="WordSkin" y="286" x="260"/> <ns1:Word skinName="WordSkin" y="296" x="270"/> <e:layout> <e:TileLayout horizontalGap="30" verticalGap="30"/> </e:layout> </e:Group> <e:Button id="btn_back" x="11" y="8"> <e:skinName> <e:Skin states="up,down,disabled"> <e:Image width="100%" height="100%" source="BackBtn_png" source.down="BackBtn1_png"/> <e:Label id="labelDisplay" horizontalCenter="0" verticalCenter="0"/> </e:Skin> </e:skinName> </e:Button> <e:Image id="img_question" width="390" height="260" y="179" horizontalCenter="0"/> <e:Group id="group_answer" width="373" height="95" x="177" y="464"> <ns1:AnswerWord skinName="WordSkin" y="478" x="185"/> <ns1:AnswerWord skinName="WordSkin" y="478" x="284"/> <ns1:AnswerWord skinName="WordSkin" y="478" x="378"/> <ns1:AnswerWord skinName="WordSkin" y="478" x="475"/> <e:layout> <e:HorizontalLayout gap="15"/> </e:layout> </e:Group> </e:Skin>
本篇已經結束,這里學習使用了自定義組件、類繼承(或說組件繼承),來搭建和設計游戲的主界面,將基礎做好,后面的開發工作就容易很多了。
本篇項目源碼:ChengyuTiaozhan3.zip(由於博客園的文件大小限制,resource資源方面請到第二篇的后面下載)