素材管理
可以直接將圖片(Gif)、聲音(mp3)、動畫、文字等素材從資源瀏覽器拖動到庫中。
資源Url
UIPackage.getItemURL(“包名“,“資源名”)
AudioClip clip = (AudioClip)UIPackage.GetItemAsset(“包名稱”,”聲音名稱”);
菜單”編輯”->“創(chuàng)建位圖字體”,(輸入字符,顯示對應(yīng)圖片)
多信息文本(GRichTextField)支持鏈接和圖文混排。
用例: aTextField.text = “請去找王大錘
”;
列表 (GList)
AddChild : 增加一個項目。
AddChildAt :在指定的位置增加一個項目。
RemoveChild : 刪除一個項目。
RemoveChildAt : 刪除一個指定位置的項目。
RemoveChildren : 刪除一個范圍內(nèi)的項目,或者全部刪除。
GList內(nèi)建了對象池。
使用對象池后的方法:
AddItemFromPool : 從池里取出(如果有)或者新建一個對象,添加到列表中
GetFromPool : 從池里取出(如果有)或者新建一個對象
ReturnToPool : 將對象返回池里
RemoveChildToPool : 刪除一個列表項目,并將對象返回池里
RemoveChildToPoolAt : 刪除一個指定位置的項目,并將對象返回池里
RemoveChildrenToPool:刪除一個范圍內(nèi)的項目,或者全部刪除,并將刪除的對象都返回池里
添加對象時不使用池,對象池將不斷增大。
正確的做法:從池中創(chuàng)建對象。即使用AddItemFromPool或GetFromPool。
虛擬列表 GList.SetVirtual
使用GList.numItems設(shè)定列表項目的數(shù)量。注意與GList.numChildren區(qū)分,后者是當(dāng)前列表容器的顯示對象數(shù)量。
但要注意顯示對象和列表項目的數(shù)量在數(shù)量上和順序上都是不一致的,也就是GetChildAt(0)獲得的顯示對象并不等于列表的第一條項目。
列表滾動到目標(biāo)位置(第500個),調(diào)用GList.AddSelection(500)
虛擬列表只能通過numItems改變列表項目的數(shù)量,不允許使用AddChild或RemoveChild增刪對象。例如如果要清空列表,必須要通過設(shè)置numItems=0,而不是RemoveChildren。
循環(huán)列表 GList.SetVirtualAndLoop()。
GList.ensureBoundsCorrect()通知GList立刻重排。(手動觸發(fā)重新排列)
裝載器 GLoader
運行時設(shè)置裝載器內(nèi)容的方式是:
aLoader.url = “ui://xxxxx”;
aLoader.url = “demo/aimage”; //這里加載的是路徑為Assets/Resources/demo/aimage的一個貼圖
例如,你希望從AssetBundle中獲取資源,那么你可以擴(kuò)展GLoader。首先編寫你的Loader類,例如:
這是一個egret中使用到的自定義loader,使用getResByUrl這個API加載外部資源。
然后我們就可以用fairygui.UIObjectFactory.setLoaderExtension(MyGLoader);注冊我們要使用的Loader類。注冊完成后,游戲中所有裝載器都是由MyGLoader實例化產(chǎn)生。
組件
點擊穿透 默認(rèn)情況下,組件的矩形區(qū)域?qū)r截點擊,勾選后,點擊事件可以穿透組件中沒有內(nèi)容的空白區(qū)域。
控制器 Controller
Controller c1 = aComponent.GetController(“c1”)
c1.selectedIndex = 1;//1是頁面索引
或
c1.selectedPage = ‘pageName’;//pageName就是頁面名稱
說明:
對所有參與的頁面,元件將分別保存不同的坐標(biāo)值;對所有沒有參與的頁面,元件將保存同一個坐標(biāo)值。
緩動功能 (位移的插值?)
按鈕控制器 Button
單選組(RadioGroup)
在程序中,要獲得或設(shè)置哪個按鈕被選中也非常簡單,使用控制器的selectedIndex或者selectedPage就可以了。
設(shè)置關(guān)聯(lián) ( 類似錨點,相對位置的設(shè)置 )
這里有一個垂直中線的關(guān)聯(lián),下面會說明,暫且不表。置可以看到,在文本內(nèi)容發(fā)生變化時,文本的中線位置沒有發(fā)生變化,位所以問號圖標(biāo)的置不變;但文本的右側(cè)位發(fā)生了變化,所以嘆號圖標(biāo)隨之發(fā)生了移動,保持了與文本右側(cè)的距離。
在代碼中設(shè)置關(guān)聯(lián)
(比如瀏覽器窗口被玩家拖大拖?。?,組件依然保持在右側(cè)位置,那么可以這樣調(diào)用:
aComoponet.addRelation(GRoot.inst, RelationType.Right_Right);
又例如希望一個動態(tài)添加到舞臺的組件始終保持滿屏大小,可以這樣調(diào)用
aComoponet.setSize(GRoot.inst.width, GRoot.inst.height);
aComoponet.addRelation(GRoot.inst, RelationType.Size);
RelationType.Size相當(dāng)于RelationType.Width_Width和RelationType.Height_Height的組合。這里強(qiáng)調(diào)一下,使組件變?yōu)闈M屏大小這個操作必須由你完成,也就是上面代碼中的setSize調(diào)用。關(guān)聯(lián)并不能完整這項任務(wù),因為關(guān)聯(lián)是不管元件當(dāng)前的大小的,它只會在目標(biāo)變化時保持兩者大小的差別。
A:和容器組件”垂直中線“關(guān)聯(lián)
B:和容器組件”右->右”關(guān)聯(lián)
C:和容器組件“右->右”,”底->底“關(guān)聯(lián)
D:和容器組件”底->底”,“垂直中線%”關(guān)聯(lián)
E:和容器組件“底->底”關(guān)聯(lián)
然后運行時把這個界面設(shè)置為滿屏就可以了。
aComponent.SetSize(GRoot.inst.width, GRoot.inst.height);
aComoponet.addRelation(GRoot.inst, RelationType.Size);//當(dāng)屏幕改變時仍然保持全屏
FairyGUI教程:(九)組件的擴(kuò)展
FairyGUI提供的控件有:
圖片(GImage)、動畫(GMovieClip)、圖形(GGraph)、文本(GTextField)、多信息文本(GRichTextFIeld)、列表(GList)、裝載器(GLoader)、組件(GComponent)。這些都是非常基礎(chǔ)的控件,他們是UI制作中的最小粒度。但僅靠這些基礎(chǔ)控件是不足以制作出各種復(fù)雜的UI界面的。我們通過”擴(kuò)展“功能,從組件(GComponent)中擴(kuò)展出來以下這些復(fù)合組件:按鈕(GButton),標(biāo)簽(GLabel),下拉框(GComboBox),進(jìn)度條(GProgressBar),滑動條(GSlider),滾動條(GScrollbar)。
可以看到有六種“擴(kuò)展”選擇。組件可以隨意在這些“擴(kuò)展”中切換。選擇哪種“擴(kuò)展”,組件就有了哪個擴(kuò)展的屬性和行為特性。
指定統(tǒng)一點擊音效
如果希望游戲中所有按鈕的點擊都有聲音反饋,你并不需要每個按鈕都設(shè)置一次聲音屬性,因為在游戲中可以使用代碼UIConfig.buttonSound=’xxx’為所有按鈕設(shè)置一個點擊聲音。
滾動條
運行時使用的滾動條需要通過以下代碼設(shè)置:
UIConfig.horizontalScrollBar = ‘xxx’;
UIConfig.verticalScrollBar = ‘yyy’;
這里xxx和yyy就是滾動條資源的url。
UIConfig.defaultScrollBarDisplay = ScrollBarDisplayType.Auto; // 設(shè)置為,滾動時顯示滾動條
9、自定義擴(kuò)展
當(dāng)基礎(chǔ)組件、擴(kuò)展組件都不能滿足你的需求時,你可以編寫自定義的擴(kuò)展。使用API UIObjectFactory.setPackageItemExtension完成定義。例如:
UIObjectFactory.setPackageItemExtension(UIPackage.getItemURL(“包名“,”組件A”), MyComponent );
public class MyComponent extends GComponent
{
override protected function constructFromXML(xml:XML):void
{
super.constructFromXML(xml);
//在這里繼續(xù)你的初始化
}
}
這樣就為組件A指定了一個實現(xiàn)類MyComponent 。以后所有組件A創(chuàng)建出來的對象(包括在編輯器里使用的組件A)都為MyComponent 類型。例如:
var obj:MyComponent = UIPackage.createObject(“包名“, ”組件A”) as MyComponent ;
注意:如果組件A只是一個普通的組件,沒有定義“擴(kuò)展”,那么基類是GComponent,如上例所示;如果組件A的擴(kuò)展是按鈕,那么MyComponent的基類應(yīng)該為GButton,如果擴(kuò)展是進(jìn)度條,那么基類應(yīng)該為GProgressBar,等等。這個不要弄錯。
控制器Tween效果
動效的播放在代碼中啟動,例如:
someComponent.GetTransition(“peng”).Play();
Play有多種原型,例如可以重復(fù)播放一定次數(shù),可以在播放結(jié)束時回調(diào)等。要中途停止動效的播放,可以調(diào)用:
someComponent.GetTransition(“peng”).Stop();
Stop方法也可以帶參數(shù),原型是
public void Stop(bool setToComplete, bool processCallback);
setToComplete表示是否將組件的狀態(tài)設(shè)置到播放完成的狀態(tài),如果否,組件的狀態(tài)就會停留在當(dāng)前時間。processCallback是否調(diào)用Play設(shè)定的播放完成回調(diào)函數(shù)。
注意:UI動效播放完畢后,組件的狀態(tài)將停留在最后一幀,而不是回到第一幀,如果你希望動效播放完后組件的狀態(tài)復(fù)原到播放前,你可以最后添加一幀重新設(shè)置組件的狀態(tài)。
高級用法:
public void SetValue(string label, params object[] aParams)
改變指定幀的數(shù)值,例如某幀Label為aa,這幀是設(shè)置某個元件的XY值的,那么調(diào)用setValue(aa, 100,200)就可以將原來此幀設(shè)置XY的數(shù)值改為100,200。
public void SetHook(string label, TransitionHook callback)
可以設(shè)定運行到某幀時發(fā)生一個調(diào)用。
多國語言支持
2、運行時動態(tài)加載語言文件。這種方法相對比較靈活。
Unity代碼片段:
string fileContent; //自行載入語言文件,這里假設(shè)已載入到此變量
FairyGUI.Utils.XML xml = new FairyGUI.Utils.XML(fileContent);
UIPackage.SetStringsSource(xml);
(十二)UI適配策略 (分辨率 設(shè)置)
GRoot.inst.setContentScaleFactor(設(shè)計分辨率寬度,設(shè)計分辨率高度,適配策略);
someComponent.setSize(GRoot.inst.width, GRoot.inst.height);// 滿屏
GRoot是FairyGUI的根組件,它的大小與屏幕分辨率的關(guān)系為
GRoot.inst.width = 屏幕寬度/GRoot.contentScaleFactor;
GRoot.inst.height = 屏幕高度/GRoot.contentScaleFactor;
(十三)顯示架構(gòu)API
FairyGUI在原生的渲染引擎上封裝了一層顯示對象結(jié)構(gòu)。
基礎(chǔ)類顯示對象:
GObject:顯示對象的基類。
GGraph:圖形對象。對應(yīng)于編輯器中顯示的一個圖形。
GImage:圖片對象。對應(yīng)于編輯器中顯示的一個圖片。
GMovieClip:動畫對象。對應(yīng)于編輯器中顯示的一個動畫。
GLoader:裝載器對象。對應(yīng)于編輯器中顯示的一個裝載器。
GTextField:文本對象。對應(yīng)于編輯器中顯示的一個文本。
GRichTextField:多媒體文本。對應(yīng)于編輯器中顯示的一個多媒體文本。
GTextInput:輸入文本對象。對應(yīng)于編輯器中顯示的一個文本,且文本類型被設(shè)置為“輸入”。
容器類顯示對象:
GComponent:組件對象。對應(yīng)于編輯器中創(chuàng)建的一個組件。
GList:列表對象。對應(yīng)于編輯器中顯示的一個列表。
容器的擴(kuò)展:
GLabel:標(biāo)簽對象。當(dāng)一個組件的擴(kuò)展為“標(biāo)簽”時,即為此類型。
GButton:按鈕對象。當(dāng)一個組件的擴(kuò)展為“按鈕”時,即為此類型。
GComboBox:組合框?qū)ο?。?dāng)一個組件的擴(kuò)展為“組合框”時,即為此類型。
GScrollBar:滾動條對象。當(dāng)一個組件的擴(kuò)展為“滾動條”時,即為此類型。
GProgressBar:進(jìn)度條對象。當(dāng)一個組件的擴(kuò)展為“進(jìn)度條”時,即為此類型。
GSlider:滑動條對象。當(dāng)一個組件的擴(kuò)展為“滑動條”時,即為此類型。
FairyGUI和Flash/Cocos類似,采用樹狀的結(jié)構(gòu)組織顯示對象。容器可以包含一個或多個基礎(chǔ)顯示對象,也可以包含容器。這個樹狀結(jié)構(gòu)稱為顯示列表。如下圖:
處于最前面的且元件范圍包含點擊位置的元件將捕獲鼠標(biāo)或觸摸事件,并且開始冒泡傳遞(請參考事件系統(tǒng) Flash/Starling/Egret/Unity)
對于組件(GComponent),寬度x高度的范圍內(nèi)點擊檢測都是有效的,無論這個范圍內(nèi)是否有子元件。舉個例子說明。組件A和組件B分別為:
將B先添加進(jìn)舞臺,然后再添加A到舞臺,也就是說,A顯示B的前面,效果如下圖:
可以看到,雖然A在B的上面,但紅色方塊是可見的,因為A在此區(qū)域并沒有內(nèi)容。當(dāng)點擊圖中綠色點的位置時,點擊事件將在A上面觸發(fā),而B是點擊不了的。這是因為在A的范圍內(nèi),點擊是不能穿透的。
如果希望A能被穿透應(yīng)該怎樣?可以通過GComponent.opaque屬性設(shè)定。當(dāng)設(shè)定為false時,這個組件將能被穿透。例如A.opaque=false,這時,只有點擊4個白塊時,A才接收到點擊事件,如果點擊綠色點位置,B將接收到點擊事件。這個特性在設(shè)計一些全屏界面時尤其要注意。也可以在編輯器里直接設(shè)定:
滾動支持
你可以在編輯器里很方便的對一個組件添加滾動特性。如果一個組件在編輯器里設(shè)置為滾動,我們可以通過GComponent.scrollPane獲得滾動控制對象。
ScrollPane提供了多個API訪問和控制滾動:
ScrollPane.percX/ScrollPane.percY:獲得或設(shè)置當(dāng)前滾動的位置,以百分比來計算,取值范圍是0-1。如果希望滾動條從當(dāng)前值到設(shè)置值有一個動態(tài)變化的過程,可以使用ScrollPane.setPercX和ScrollPane.setPercY,這兩個API提供了一個是否使用緩動的參數(shù)。
ScrollPane.posX/ScrollPane.posY:獲得或設(shè)置當(dāng)前滾動的位置,以像素來計算。取值范圍決定于當(dāng)前顯示的內(nèi)容大小與視口大小的差別。例如,一個垂直滾動的組件,如果視口大小為100像素,實際內(nèi)容大小為300像素,那么posY的取值范圍是0~200像素,當(dāng)posY=200時,滾動條滾動到最下方。posX/posY與percX/percY不同在于,除非開發(fā)者自己設(shè)置或者用戶拖動滾動條,percX/percY是不變的,舉個例子,當(dāng)前某滾動容器的percX=0.1, posX=100,如果往容器里添加一定內(nèi)容后,內(nèi)容的寬度增大,percX的值仍將保持不變,依然是0.1,但posX的值會發(fā)生相應(yīng)的改變。所以如果希望容器內(nèi)增刪內(nèi)容后滾動條不發(fā)生滾動,可以先記錄posX/posY的位置,添加完之后再設(shè)置posX/posY為此前記錄的位置。
ScrollPane.scrollToView:調(diào)整滾動位置,使指定的元件出現(xiàn)在視口內(nèi)。
窗口系統(tǒng)
窗口使用前首先要設(shè)置窗口中需要顯示的內(nèi)容,這通常是在編輯器里制作好的,可以直接使用Window.contentPane進(jìn)行設(shè)置。建議把設(shè)置contentPane等初始化操作放置到Window.onInit方法中。
另外,F(xiàn)airyGUI還提供了一套機(jī)制用于窗口動態(tài)創(chuàng)建。動態(tài)創(chuàng)建是指初始時僅指定窗口需要使用的資源,等窗口需要顯示時才實際開始構(gòu)建窗口的內(nèi)容。首先需要在窗口的構(gòu)造函數(shù)中調(diào)用Window.addUISource。這個方法需要一個IUISource類型的參數(shù),而IUISource是一個接口,用戶需要自行實現(xiàn)載入相關(guān)UI包的邏輯。當(dāng)窗口第一次顯示之前,IUISource的加載方法將會被調(diào)用,并等待載入完成后才返回執(zhí)行Window.OnInit,然后窗口才會顯示。
調(diào)用Window.show顯示窗口的流程:
如果你需要窗口顯示時播放動畫效果,那么覆蓋doShowAnimation編寫你的動畫代碼,并且在動畫結(jié)束后調(diào)用onShown。
覆蓋onShown編寫其他需要在窗口顯示時處理的業(yè)務(wù)邏輯。
調(diào)用Window.hide隱藏窗口的流程:
如果你需要窗口隱藏時播放動畫效果,那么覆蓋doHideAnimation編寫你的動畫代碼,并且在動畫結(jié)束時調(diào)用Window.hideImmediately(注意不是直接調(diào)用onHide?。?/p>
覆蓋onHide編寫其他需要在窗口隱藏時處理的業(yè)務(wù)邏輯。
通常窗口會包括一個可用于拖動的標(biāo)題欄,關(guān)閉按鈕等。我們在編輯器創(chuàng)建窗口組件時,可以為它創(chuàng)建一個名稱為frame的組件,frame組件的擴(kuò)展應(yīng)該選擇為“標(biāo)簽”,這樣外部組件能夠為其設(shè)置圖標(biāo)和標(biāo)題屬性。frame組件中約定的內(nèi)容還包括:
closeButton:一個名稱為closeButton的按鈕將自動作為窗口的關(guān)閉按鈕。
dragArea:一個名稱為dragArea的圖形(類型設(shè)置為空白)將自動作為窗口的檢測拖動區(qū)域,當(dāng)用戶在此區(qū)域內(nèi)按住并拖動時,窗口隨之被拖動。
contentArea:一個名稱為contentArea的圖形(類型設(shè)置為空白)將作為窗口的主要內(nèi)容區(qū)域,這個區(qū)域只用于Window.showModalWait。當(dāng)調(diào)用Window.showModalWait時,窗口會被鎖定,如果設(shè)定了contentArea,則只鎖定contentArea指定的區(qū)域,否則鎖定整個窗口。如果你希望窗口在modalWait狀態(tài)下依然能夠拖動和關(guān)閉,那么就不要讓contentArea覆蓋標(biāo)題欄區(qū)域。
注意以上的約定均為可選,是否含有組件frame,或者組件frame里是否含有約定的功能組件,并不會影響窗口的正常顯示和關(guān)閉。
Popup管理
在UI系統(tǒng)中我們經(jīng)常需要一些彈出一些組件,這些組件在用戶點擊空白地方的情況下就會自動消失,又或者由開發(fā)者控制消失。GRoot提供了幾個API管理這些Popup組件。
GRoot.showPopup:彈出一個組件,如果指定了目標(biāo),則會調(diào)整彈出的位置到目標(biāo)的下方,形成一個下拉的效果。同時提供了參數(shù)可以用來指定是向上彈出或者向下彈出。
GRoot.hidePopup: 默認(rèn)情況下,用戶點擊空白地方就會自動關(guān)閉彈出的組件。也可以調(diào)用此API手工關(guān)閉。不指定參數(shù)時,所有當(dāng)前的彈出都關(guān)閉。
FairyGUI會根據(jù)組件的大小自動計算彈出位置,以確保組件顯示不會超出屏幕。
(十五)事件系統(tǒng):Unity
發(fā)表回復(fù)
Unity平臺參考了Flash的事件機(jī)制,設(shè)計了自己獨特的事件系統(tǒng)。EventDispatcher是事件分發(fā)的中心,GObject就是一個EventDispatcher。每個事件類型都對應(yīng)一個EventListener,接收事件并調(diào)用處理函數(shù)。例如需要編寫某個元件單擊的處理邏輯:
aObject.onClick.Add(aCallback);
void aCallback()
{
//some logic
}
事件回調(diào)函數(shù)
每個事件可以注冊一個或多個回調(diào)函數(shù)。函數(shù)原型為:
public delegate void EventCallback0();
public delegate void EventCallback1(EventContext context);
函數(shù)可以不帶參數(shù)或帶一個參數(shù)。
EventContext
EventContext是回調(diào)函數(shù)的參數(shù)類型。
EventContext.sender:獲得事件的分發(fā)者。
EventContext.initiator:獲得事件的發(fā)起者。一般來說,事件的分發(fā)者和發(fā)起者是相同的,但如果事件已發(fā)生冒泡,則可能不相同。參考下面冒泡的描述。
EventContext.type:事件類型。
EventContext.inputEvent:如果事件是鍵盤/觸摸/鼠標(biāo)事件,通過訪問inputEvent對象可以獲得這類事件的相關(guān)數(shù)據(jù)。
EventContext.data:事件的數(shù)據(jù)。根據(jù)事件不同,可以有不同的含義。
事件冒泡和事件捕獲
一些特殊的事件,比如鼠標(biāo)/觸摸事件,具備向父組件傳遞的特性,這個傳遞過程叫做冒泡。例如當(dāng)手指接觸A元件時,A元件觸發(fā)TouchBegin事件,然后A元件的父組件B觸發(fā)TouchBegin事件,然后B的父組件C也觸發(fā)TouchBegin事件,以此類推,直到舞臺根部。這個設(shè)計保證了所有關(guān)聯(lián)的顯示對象都有機(jī)會處理觸摸事件,而不只是最頂端的顯示對象。
冒泡過程可以被打斷,通過調(diào)用EventContext.StopPropagation()可以使冒泡停止向父組件推進(jìn)。
從上面的冒泡過程可以看出,事件處理的順序應(yīng)該是:A’s listeners->B’s listeners->C’s listeners,這里還有一種機(jī)制可以讓鏈路上任意一個對象可以提前處理事件,這就是事件捕獲。事件捕獲是反向的,例如在上面的例子中,就是C先捕獲事件,然后是B,再到A。所以所有事件處理的完整順序應(yīng)該是:
C’s capture listeners->B’s capture listeners->A’s capture listeners->A’s listeners->B’s listeners->C’s listeners
捕獲傳遞鏈?zhǔn)遣荒苤兄沟模芭輦鬟f鏈可以通過StopPropagation中止。
事件捕獲的設(shè)計可以使父元件優(yōu)于子元件和孫子元件檢查事件。
并非所有事件都有冒泡設(shè)計,請參考下面關(guān)于各個事件的說明。并非只有冒泡事件才有捕獲設(shè)計。在非冒泡事件中,capture的回調(diào)優(yōu)于普通回調(diào),僅此而已,可以作為一個優(yōu)先級特性來使用。
InputEvent
對鍵盤事件和鼠標(biāo)/觸摸事件,可以通過EventContext.inputEvent獲得此類事件的相關(guān)數(shù)據(jù)。InputEvent.x/InputEvent.y:鼠標(biāo)或手指的位置;這是舞臺坐標(biāo),因為UI可能因為自適配發(fā)生了縮放,所以如果要轉(zhuǎn)成UI元件中的坐標(biāo),要使用GObject.GlobalToLocal轉(zhuǎn)換。
InputEvent.keyCode:按鍵代碼;
InputEvent.modifiers:參考UnityEngine.EventModifiers。
InputEvent.mouseWheelDelta:鼠標(biāo)滾輪滾動值。
InputEvent.touchId:拖動使用手指;在PC平臺,該值為0,沒有意義。
InputEvent.isDoubleClick:是否雙擊。
EventListener
EventListener.Add/EventListener.Remove:添加或刪除一個回調(diào),回調(diào)函數(shù)可以帶一個參數(shù)或者不帶參數(shù)。參數(shù)的類型是object,它的實際含義隨不同事件不同而不同;
EventListener.AddCapture/EventListener.RemoveCapture:添加或刪除一個捕獲期回調(diào)。
事件類型
GObject.onClick:單擊。冒泡事件。事件數(shù)據(jù)為InputEvent對象。
GObject.onRightClick:右鍵單擊。冒泡事件。事件數(shù)據(jù)為InputEvent對象。
GObject.onTouchBegin:鼠標(biāo)或手指按下。冒泡事件。事件數(shù)據(jù)為InputEvent對象。
GObject.onTouchEnd:鼠標(biāo)或手指釋放。冒泡事件。事件數(shù)據(jù)為InputEvent對象。
GObject.onRollOver:鼠標(biāo)移入元件。事件數(shù)據(jù)為InputEvent對象。
GObject.onRollOut:鼠標(biāo)移出元件。事件數(shù)據(jù)為InputEvent對象。
GObject.onAddedToStage:元件被添加到舞臺。無事件數(shù)據(jù)。
GObject.onRemovedFromStage:元件從舞臺移出。無事件數(shù)據(jù)。
GObject.onKeyDown:元件接收到按鍵事件。只有獲得焦點的情況下才能接收按鍵事件。冒泡事件。事件數(shù)據(jù)為InputEvent對象。
GObject.onClickLink:文本中的鏈接被點擊。事件數(shù)據(jù)為href值,字符串類型。
GObject.onPositionChanged:元件的位置改變。無事件數(shù)據(jù)。
GObject.onSizeChanged:元件的大小改變。無事件數(shù)據(jù)。
GObject.onDragStart/GObject.onDragEnd:拖動是指玩家按住元件拖動然后釋放的過程。注意只有設(shè)置了GObject.draggable屬性的元件才會觸發(fā)拖動事件。拖動過程中可以獲得兩個通知:開始和結(jié)束。當(dāng)onDragStart中,調(diào)用EventContext.PreventDefault()可以立刻取消拖動。無事件數(shù)據(jù)。
GTextField.onFocusIn/GTextField.onFocusOut:只有輸入類型的文本才會觸發(fā)這個事件。當(dāng)輸入文本獲得焦點時,在移動設(shè)備上會彈出小鍵盤。無事件數(shù)據(jù)。
GTextField.onChanged:只有輸入類型的文本才會觸發(fā)這個事件。無事件數(shù)據(jù)。
GMovieClip.onPlayEnd:動畫設(shè)定的播放次數(shù)已經(jīng)播放完畢。無事件數(shù)據(jù)。
GList.onClickItem:當(dāng)GList容器內(nèi)的元件被點擊時觸發(fā)的事件類型;事件數(shù)據(jù)為當(dāng)前點擊的GObject對象。
GComponent.onScroll:如果容器是滾動類型容器,則滾動發(fā)生時產(chǎn)生該事件。
GComponent.onDrop:注意要和普通拖動區(qū)別,一個元件被拖動并釋放后并不會觸發(fā)Drop事件。Drop事件需配合DragDropManager使用。當(dāng)DragDropManager拖動的圖標(biāo)在某個元件上釋放時,這個元件就會觸發(fā)onDrop。事件數(shù)據(jù)為DragDropManager.StartDrag中傳遞的source值。
GButton.onChanged:當(dāng)單選或者多選按鈕選中狀態(tài)改變時會觸發(fā)該事件(只有在用戶點擊后狀態(tài)改變才會觸發(fā),如果是程序改變不會觸發(fā))。無事件數(shù)據(jù)。
GComboBox.onChanged:當(dāng)用戶從下拉列表中選擇一項時觸發(fā)該事件。無事件數(shù)據(jù)。
GSlider.onChanged:當(dāng)用戶拖動滑塊改變Slider的值時觸發(fā)該事件。無事件數(shù)據(jù)。
Controller.onChanged:當(dāng)控制器頁面改變會觸發(fā)該事件(改變selectedIndex會觸發(fā)該事件,setSelectedIndex則不會)。無事件數(shù)據(jù)。
(十八)在Unity項目中使用FairyGUI
1. 使用UIPanel
只需3步就可以使用將編輯器中制作好的界面放入到Unity的場景中。第一步,從GameObject菜單中選擇FairyGUI->UIPanel:
第二步,在Inspector里點擊PackageName或者ComponentName,將彈出選擇組件的窗口:
第三步:這個窗口里列出了所有工程里能找到的UI包,選擇一個包和組件,然后點擊OK。
可以看到,UI組件的內(nèi)容顯示出來了。(注意:Unity4版本目前不支持顯示內(nèi)容,只能顯示線框)
如果UI包修改了,或者其他一些情況導(dǎo)致UIPanel顯示不正常,可以使用下面的菜單刷新:
當(dāng)運行后,獲得UIPanel的UI的方式是:
UIPanel panel = gameObject.GetComponent();
GComponent view = panel.ui;
與其他UIPackage.CreateObject創(chuàng)建出來的界面不同,UIPanel在GameObjec銷毀時(手動銷毀或者過場景等)時會一并銷毀。
UIPane只保存了UI包的名稱和組件的名稱,它不對紋理或其他資源產(chǎn)生任何引用,也就是UI使用的資源不會包含在場景數(shù)據(jù)中。
在編輯狀態(tài)下,無論UI組件引用了哪些UI包的資源,包括放置在Resources目錄下的和不放置在Resources下的,都能夠正確顯示。但當(dāng)運行后,UIPanel只能自動載入放置在Resources目錄或其子目錄下的UI包,也只會載入自身所在的UI包,其他情況的UI包(例如引用到的UI包或打包到AssetBundle的UI包)不能自動載入。你需要在UIPanel創(chuàng)建前使用UIPackage.AddPackage準(zhǔn)備好這類UI包。UIPanel在Start事件或者第一次訪問UIPanel.ui屬性時創(chuàng)建UI界面,你仍然有機(jī)會在Awake里完成這些操作。
下面是UIPanel的一些屬性說明:
Render Mode: 有三種:
Screen Space Overlay (默認(rèn)值),表示這個UI在屏幕空間顯示,這時Transform的Scale將被鎖定,而且不建議修改Transform中的其他內(nèi)容(讓他們保持為0)。如果要修改面板在屏幕上的位置,使用UI Transform(參考下面關(guān)于UI Transform的說明)。
Screen Space Camera 表示這個UI在屏幕空間顯示,但不使用FairyGUI默認(rèn)的正交相機(jī),而是使用指定的正交相機(jī)。
World Space 表示這個UI在世界空間顯示,由透視相機(jī)渲染。默認(rèn)的使用場景的主相機(jī),如果不是,那么設(shè)置Render Camera。當(dāng)使用這種模式時,使用Transfrom修改UI在世界空間中的位置、縮放、旋轉(zhuǎn)。但你仍然可以使用UI Transform。
注意:Render Mode只定義了FairyGUI對待這個UI的方式,通常是坐標(biāo)相關(guān)的操作(如點擊檢測等),但和渲染無關(guān)。UI由哪個相機(jī)渲染是由GameObject的layer決定的。所以如果發(fā)現(xiàn)UI沒有顯示出來,可以檢查一下GameObject的layer是否正確。例如如果是Screen Space,GameObject應(yīng)該在UI層,如果是WorldSpace,則是在Default層或者其他自定義的層次。
Render Camera:當(dāng)Render Mode是Screen Space Camera或者World Space時可以設(shè)置。如果不設(shè)置,默認(rèn)為場景的主相機(jī)。
Sorting Order:調(diào)整UIPanel的顯示順序。越大的顯示在越前面。
Fairy Batching:是否啟用Fairy Batching。關(guān)于Fairy Batching請參考下面的說明。切換這個值,可以在編輯模式下實時看到DrawCall的變化(切換后點擊一下Game,Stat里顯示的內(nèi)容才會更新),這可以使你更加容易決定是否啟用這項技術(shù)。
Touch Disabled:勾選后,將關(guān)閉點擊檢測。當(dāng)這個UI沒有可交互的內(nèi)容時可以勾選以提高點擊檢測時的性能。例如頭頂血條這些類型的UI,就可以勾選。
UI Transform:當(dāng)Render Mode是Screen Space時可以使用這里的設(shè)置調(diào)整UI在屏幕上的位置。你仍然可以調(diào)整Transform改變UI的位置,但我不建議你這樣做,因為Transform中的坐標(biāo)位置是沒有經(jīng)過不同分辨率自適應(yīng)的調(diào)整的。當(dāng)Render Mode是World Space時,建議使用Transform設(shè)置UI的位置,你仍然可以調(diào)整UI Transform改變UI的位置,但調(diào)整的效果可能不那么直觀。同時你可以使用Scene視圖中下圖所示的原點調(diào)整UI Transform的位置屬性:
Fit Screen:這里可以設(shè)置UIPanel適配屏幕。
Fit Size:UI將鋪滿屏幕。
Fit Width And Set Middle:UI將橫向鋪滿屏幕,然后上下居中。
Fit Height And Set Center:UI將縱向鋪滿屏幕,然后左右居中。
這里提供的選項不多,因為FairyGUI推薦的是在FairyGUI編輯器中整體設(shè)計,而不是在Unity里擺放小元件。例如如果需要不同的UI在屏幕上的各個位置布局,你應(yīng)該在FairyGUI編輯器中創(chuàng)建一個全屏大小的組件,然后在里面放置各個子組件,再用關(guān)聯(lián)控制布局;最后將這個全屏組件放置到Unity,將Fit Screen設(shè)置為Fit Size即可。錯誤的做法是把各個子組件放置到Unity里再布局。
HitTest Mode:這里可以設(shè)置UIPanel處理鼠標(biāo)或觸摸事件的方式。
Default: 這是默認(rèn)的方式。FairyGUI會用內(nèi)置的機(jī)制檢測鼠標(biāo)或觸摸動作,不使用射線,UIPanel也不需要創(chuàng)建碰撞體,效能比較高。
Raycast: 在這種方式下,UIPanel將自動創(chuàng)建碰撞體,并且使用射線方式進(jìn)行點擊檢測。這種方式適合于UIPanel還需要和其他3D對象互動的情況。
2. 動態(tài)載入UI界面
在很多情況下,你并不需要將UI界面放到場景中。使用代碼載入編輯器制作好的界面也非常簡單:
GComponent view = UIPackage.CreateObject(“包名”, “組件名”) as GComponent
動態(tài)載入的界面不會自動銷毀,例如一個背包窗口,你并不需要在每次過場景都銷毀。如果要銷毀界面,調(diào)用Dispose方法即可,例如
view.Dispose();
也可以動態(tài)創(chuàng)建UIPanel為任意游戲?qū)ο髵旖覷I界面,方法為:
UIPanel panel = yourGameObject.AddComponent();
panel.packageName = “包名”;
panel.componentName = “組件名”;
panel.CreateUI();
UIPanel的生命周期將和yourGameObject保持一致。再次提醒,注意yourGameObject的layer。
3. 載入UI包
Unity項目載入UI包有以下幾種方式,開發(fā)者可以根據(jù)項目需要選擇其中一種或者多種混搭使用:
1)將打包后的文件直接發(fā)布到Unity的Resources目錄或者其子目錄下,
然后在代碼中調(diào)用UIPackage.AddPackage(“demo”), demo就是發(fā)布時填寫的文件名。如果在子目錄下,調(diào)用UIPackage.AddPacakge(“路徑/demo”)即可。
2)將發(fā)布后的文件打包為兩個AssetBundle,即定義文件和資源各打包為一個bundle(desc_bundle+res_bundle)。這樣做的好處是一般UI的更新都是修改元件位置什么的,不涉及圖片資源的更新,那么只需要重新打包和推送desc_bundle就行了,不需要讓玩家更新通常體積比較大的res_bouble,節(jié)省流量。打包程序由開發(fā)者按照自己熟悉的方式自行實現(xiàn)。以demo為例,請遵循以下規(guī)則打包:
a)demo.bytes單獨打包為desc_bundle;
b)其他資源(demo@atlas0.png等),打包到res_bundle(在此例中就是atlas0和sprites)
然后在代碼中調(diào)用UIPackage.AddPackage(desc_bundle, res_bundle)。bundle的載入由開發(fā)者自行實現(xiàn)。
3)將發(fā)布后的文件打包為一個AssetBundle。打包程序由開發(fā)者按照自己熟悉的方式自行實現(xiàn)。以demo為例,將demo.bytes和其他資源(demo@atlas0.png等),都放入bundle。然后在代碼中調(diào)用UIPackage.AddPackage(bundle, bundle)。bundle的載入由開發(fā)者自行實現(xiàn)。
在使用AssetBundle的載入方案中,將由FairyGUI接管bundle并負(fù)責(zé)bundle資源的釋放。
4. UI適配
可以通過兩種方式設(shè)置UI自適應(yīng),第一種方式是在游戲的啟動創(chuàng)建里任意對象掛一個FairyGUI/UIContentScaler組件:
這里選項的含義可以參考教程里關(guān)于UI適配的說明。
另外一種方式是通過代碼,可以參考教程里關(guān)于UI適配的說明。
5.圖集的處理
FairyGUI編輯器發(fā)布到Unity的資源通常包含一個或多個UI圖集,以demo工程為例,這里demo@atlas0.png就是一個圖集
圖集是由UI編輯器自動生成的,但在Unity里可以改變圖集的屬性,常用的設(shè)置有:
1)Generate Mip Maps
不勾選。UI不使用Mip Maps功能。
2)Filter Mode
使用Bilinear,這樣圖像在縮放時能產(chǎn)生比較平滑的過渡效果,副作用是會產(chǎn)生一定的模糊。而且單色的圖像縮放會產(chǎn)生不必要的漸變邊緣。而使用Point,則圖像在縮放時會塊狀化。
一般UI圖集使用Bilinear即可。你也可以在UI編輯器里將圖片安排到不同圖集,然后每個圖集設(shè)置不同的Filter Mode以滿足特殊需求。
3)Max Size
一般設(shè)置到2048。
4)Format
UI圖集一般都是PNG格式,并帶有透明通道。同時,UI對畫質(zhì)的要求比較高,所以建議選擇AutoMatic TrueColor。但TrueColor有一個最大的問題是文件大,而且占用內(nèi)存較高,例如1024×1024的圖集,將占用4MB的內(nèi)存,2048×2048則達(dá)到16MB。
如果對內(nèi)存使用比較敏感,也可以選用壓縮格式,即AutoMatic Compressed。在桌面平臺上即相同于DXT5,在Android平臺上相當(dāng)于ETC1,在IPhone平臺則為PVRTC。這些格式能夠大大降低內(nèi)存占用,也因為它們是顯卡直接支持的格式,所以Unity在載入時省去了解碼位圖的步驟,能夠加快載入速度。但它們都是屬于有損壓縮,在顯示質(zhì)量上肯定不如TrueColor,特別是圖集顏色十分豐富,或者有顏色漸變時,失真會比較厲害。特別重要的是,ETC1是不支持透明通道的,PVRTC對透明通道的支持也比較弱,所以并不適合帶透明通道的圖集。FairyGUI提供了ETC1/PVRTC+A的解決方案。首先,在發(fā)布時勾選“為Alpha通道創(chuàng)建單獨的貼圖”,如下圖:
這樣,就產(chǎn)生了兩個不含透明通道的貼圖,一張去除了原圖透明通道的貼圖,和一張將原貼圖透明通道數(shù)值轉(zhuǎn)換為等價灰度的貼圖。這兩張貼圖都可以設(shè)置為Automatic Compressed。(一定要注意,不能再將主貼圖設(shè)置為True Color)
FairyGUI提供了特制的著色器處理兩張貼圖的合并。開發(fā)者并不需要編寫額外的代碼就可以使用這項技術(shù)。
TIPS
你可以將本身就不含透明通道的位圖(例如一些大型的背景圖)安排到一張圖集上。如果一張圖集內(nèi)的所有圖片都不包含透明通道,那么最終輸出的圖集也不包含透明通道。不含透明通道的圖集可以選用Automatic 16bits格式。
6. 字體的處理
FairyGUI使用Unity的動態(tài)字體技術(shù)渲染文字。只需以下幾個簡單的步驟就可以完成設(shè)置:
1)拷貝一個字體文件到項目的Resources目錄或Resources/Fonts目錄。字體文件可以隨意使用一個,例如arial.ttf,或simhei.ttf等,這個ttf是什么字體并不影響最終顯示字體的選擇。
2)在Unity中點擊字體文件,在inspector中修改字體屬性
注意在Font Names中填寫的是字體名稱,標(biāo)準(zhǔn)的字體名稱可以從這里找到: 中文字體的英文名稱對照表。例如Droid Sans Fallback是Android平臺支持中文的內(nèi)置默認(rèn)字體之一。多個字體用逗號隔開,Unity會使用第一個在系統(tǒng)中能找到的字體。
3)設(shè)置UIConfig.defaultFont=”字體文件名稱”即可,注意這里使用的是文件名稱,也就是說,如果放置在Resources目錄的是arial.ttf,則UIConfig.defaultFont=”arial”,不需要帶.ttf后綴。
因為我們沒有勾選Include Font Data,所以無論這個字體文件有多大,最終并不會包含在我們的發(fā)布包中,也就是說不會增大發(fā)行包的體積。Unity會在實際運行的系統(tǒng)中查找與Font Names匹配的第一個字體,并使用此字體進(jìn)行動態(tài)渲染。
如果你是在Unity5.x平臺開發(fā),除了上述方式外,得益于Unity5.x引入的新的字體管理API,也可以不放置字體文件到Resources目錄,你只需要直接設(shè)置UIConfig.defaultFont=”字體名稱“即可,同樣,多個字體名稱用逗號隔開。例如:UIConfig.defaultFont=”Droid Sans Fallback, LTHYSZK, Helvetica-Bold, Microsoft YaHei, SimHei”;
4)如果你的界面使用了多種字體,比如對單獨的文字設(shè)置了字體:
這里用到了“黑體”這個名字的字體,這是與UIConfig.defaultFont里設(shè)置的不同的字體,我們也需要注冊這種字體。方法是,首先做好上面1)和2),假如字體文件名稱是HeiTi.ttf,然后
FontManager.RegisterFont(“黑體”, FontManager.GetFont(“HeiTi”));
RegisterFont的第一個參數(shù)對應(yīng)編輯器里使用的字體名稱;第二個參數(shù),是Unity中放入的字體文件資源。如果文件帶路徑,這也需要把路徑填上。
5)當(dāng)你使用部分字體的粗體效果時,你會發(fā)現(xiàn)粗體的效果在Unity中的顯示不正確,這是因為有些字體不帶粗體效果的,這時候Unity就會用拉寬來實現(xiàn),就像變扁了。fairygui可以用額外的mesh來解決粗體的顯示。方法是:
FontManager.GetFont(“字體路徑”).customFold = true;
這里字體路徑與UIConfig.default里設(shè)置的內(nèi)容應(yīng)該完全一樣。
6)某些字體,unity渲染有粗體效果,但當(dāng)設(shè)置成斜體時,粗體效果又丟失(例如雅黑)。fairygui在這種情況取消unity默認(rèn)渲染粗體的效果,改為增加額外的面渲染粗體。激活這個功能的方法是
FontManager.GetFont(“字體路徑”).customBoldAndItalic = true;
如果已經(jīng)設(shè)置了customBold,不需要再設(shè)置customBoldAndItalic。
備注1
動態(tài)字體要求玩家的運行系統(tǒng)環(huán)境中有你設(shè)定的字體,如果沒有,實際使用的字體可能并不是你想要的效果。因此,你可以選擇嵌入整個字體文件。方法是把你要用的字體文件放到Resources目錄,并把Include Font Data勾選,這樣整個字體文件就會包含到最終的發(fā)布包中,壞處就是會大大增加發(fā)行包的體積。
備注2
在實際游戲制作過程中發(fā)現(xiàn)在桌面平臺下Unity對中文字體的渲染稍顯模糊和暗淡,因此FairyGUI使用了特制的著色器解決了這個問題。以下是Unity默認(rèn)的字體渲染效果和FairyGUI的字體渲染效果的比較:
可以看見經(jīng)過FairyGUI的特殊處理,中文文字更清晰更亮。
只有在桌面平臺下FairyGUI才會開啟這種技術(shù),移動平臺永遠(yuǎn)不會開啟,因為在高DPI情況下,字體默認(rèn)的渲染效果已經(jīng)非常漂亮。
另外,如果你不喜歡這種顯示效果,或者你使用的是全英文的文字,也可以手動把這種技術(shù)關(guān)閉:UIConfig.renderingTextBrighterOnDesktop = false;
7 在UI中穿插其他3D對象
FairyGUI底層使用Renderer.sortingOrder來決定對象的渲染順序,利用這個特性,我們可以很容易的將UI對象與其他3D對象(例如例子)安排在一起。FairyGUI提供了封裝類GoWrapper,可以直接包裝其他GameObject插入到UI層次中。如下圖,一個粒子特效被安排到了UI之間。
又例如,一個3D模型穿插在UI中間
詳細(xì)實現(xiàn)方法可以參考FairyGUI-unity包中的Assets/FairyGUI/Examples/Particles和Assets/FairyGUI/Examples/Model。
8. 與RenderTexture配合
在UI上展現(xiàn)3D內(nèi)容的另一種方式是使用RenderTexture,特別是需要進(jìn)行剪裁的情況下(如果不需要剪裁,推薦直接放置3D內(nèi)容,免除RenderTexture性能消耗。參考6. 在UI中穿插其他3D對象)。在FairyGUI中,可以將Image.texture設(shè)置為一個RenderTexture,然后就可以像使用普通圖片一樣使用這個RenderTexture了,可以出現(xiàn)在任何地方,包括滾動容器。特別地,F(xiàn)airyGUI還能支持將RenderTexture所在位置的背景圖片影射到RenderTexture渲染相機(jī)的背景上,這樣就不用擔(dān)心透貼的問題了。如下圖,NPC使用RenderTexture渲染到UI窗口中。
詳細(xì)實現(xiàn)方法可以參考FairyGUI-unity包中的Assets/FairyGUI/Examples/RenderTexture。
9. Drawcall優(yōu)化
在Unity中,每次引擎準(zhǔn)備數(shù)據(jù)并通知GPU的過程稱為一次Draw Call(DC)。Draw Call次數(shù)是一項非常重要的性能指標(biāo)。UI系統(tǒng)一般包含數(shù)量眾多的物體,有效控制DC是衡量一個UI系統(tǒng)是否實用的關(guān)鍵因素,特別是在移動設(shè)備上。
我們先來看看NGUI是怎么做的,NGUI把UIPanel中的Widget按depth排序,然后將相同材質(zhì)的Widget進(jìn)行Mesh合并,例如使用相同圖集的圖片,或者文字。Mesh合并的優(yōu)點是合并后這些Widget就只產(chǎn)生一個DC。但這個合并過程需要計算所有Widget坐標(biāo)相對于Panel的變換,而且如果Widget行為改變,例如平移,縮放等,都會觸發(fā)Mesh重新合并,這會帶來一定的CPU消耗,這就需要開發(fā)者謹(jǐn)慎組織UI元素到各個UIPanel,并且對深度需要細(xì)致安排,否則達(dá)不到減少DC效果的同時更可能帶來比較大的CPU消耗。
FairyGUI沒有采取合并Mesh的策略,原因有兩個:
● FairyGUI使用的是樹狀顯示對象結(jié)構(gòu),各個元件之間的層次關(guān)系非常復(fù)雜;
● FairyGUI編輯器給予用戶最大的設(shè)計自由度,加上動效的引入,各個元件的狀態(tài)都可能非常動態(tài);
FairyGUI基于Unity的Dynamic Batching技術(shù),提供了深度調(diào)整技術(shù)進(jìn)行 drawcall優(yōu)化 。FairyGUI能在不改變最終顯示效果的前提下,盡可能的把相同材質(zhì)的物體調(diào)整到連續(xù)的renderingOrder值上,以促使他們能夠被Unity Dynamic Batching優(yōu)化。Dynamic Batching是Unity提供的Draw Call Batching技術(shù)之一。如果動態(tài)物體共用著相同的材質(zhì),那么Unity會自動對這些物體進(jìn)行批處理。但Dynamic Batching的一個重要的前提是這些動態(tài)物體是連續(xù)渲染的。先來看看FairyGUI中物體的渲染順序,例如:
這里有4個按鈕,每個按鈕都是一個組件,每個組件里包含一個圖片和一個文字對象。FairyGUI是樹狀的顯示對象結(jié)構(gòu),那么他們按深度排序應(yīng)該是:
因為文字和圖片的材質(zhì)并不相同,所以每次從文字到圖片都產(chǎn)生上下文切換,所以產(chǎn)生了6個DC。
FairyGUI的深度調(diào)整技術(shù)可以優(yōu)化這種情況。觀察一下,其實四個按鈕之間并不相交,所以FairyGUI智能地將渲染順序調(diào)整為:
因為FairyGUI使用了圖集,而且動態(tài)文字也使用了相同的貼圖,這樣,DC就降低到了2個,達(dá)到了優(yōu)化的目的。實際情況會比這個復(fù)雜很多,但FairyGUI能在不改變最終顯示效果的前提下,盡可能的把相同材質(zhì)的物體調(diào)整到連續(xù)的renderingOrder值上,以促使他們能夠被Unity Dynamic Batching優(yōu)化。而對開發(fā)者來說,這些底層上的調(diào)整是透明的,也就是不會影響原來的顯示對象層次。從效率上考慮,這種技術(shù)僅比較物體之間的顯示矩形區(qū)域(一個Rect)是否相交,所以速度是非??斓?,不會帶來過多的CPU負(fù)荷。
FairyGUI提供了一個開關(guān)控制組件是否啟用深度調(diào)整,API是:
GComponent someComponent;
someComponent.fairyBatching = true;
如果某個組件設(shè)置了fairyBatching,那么無需在子組件和孫子組件再啟用fairyBatching。一般只在頂層組件打開這個功能,例如主界面,加載界面等。注意,Window這個類已經(jīng)自動打開了fairyBatching,這符合我們的使用習(xí)慣,因為一般我們都是以窗口為單位安排功能的。如果界面不復(fù)雜,Draw Call本來就不高的情況下,開發(fā)者也可以忽略這個功能,從10個DC優(yōu)化到8個DC并沒有什么意義。在實際使用過程中,
對于打開了fairyBatching的組件,當(dāng)開發(fā)者動態(tài)改變子元件或者孫子元件的位置或大小時,并不會自動觸發(fā)深度調(diào)整,例如一個圖片原來顯示在一個窗口里的頂層,你用Tween將它從原來的位置移到另外一個位置,這個圖片就有可能被窗口里的其他元素遮擋。這時開發(fā)者可以手動觸發(fā)深度調(diào)整,API是
someObject.InvalidateBatchingState();
這個API并不需要由開啟了fairyBatching的組件調(diào)用,它可以用任何一個內(nèi)含的元件發(fā)起。對于UI動效(Transitions),F(xiàn)airyGUI已經(jīng)自動調(diào)用了這個API,所以開發(fā)者不必處理。
下載并運行Demo,可以觀察fairyBatching的實際效果。例如這個Demo的首頁:
設(shè)置了fairyBatching后由42個DC減少到了6個DC,另外,可以看到Saved by batching: 27的字樣。
與ULUA配合
一、安裝
1、將以下語句添加到Assets\uLua\Editor\WrapFile.cs適當(dāng)?shù)奈恢茫缓笳{(diào)用Lua的菜單Gen Lua Wrap Files,重新生成綁定文件。
_GT(typeof(EventContext)),
_GT(typeof(EventDispatcher)),
_GT(typeof(EventListener)),
_GT(typeof(InputEvent)),
_GT(typeof(DisplayObject)),
_GT(typeof(Container)),
_GT(typeof(Stage)),
_GT(typeof(Controller)),
_GT(typeof(GObject)),
_GT(typeof(GGraph)),
_GT(typeof(GGroup)),
_GT(typeof(GImage)),
_GT(typeof(GLoader)),
_GT(typeof(PlayState)),
_GT(typeof(GMovieClip)),
_GT(typeof(TextFormat)),
_GT(typeof(GTextField)),
_GT(typeof(GRichTextField)),
_GT(typeof(GTextInput)),
_GT(typeof(GComponent)),
_GT(typeof(GList)),
_GT(typeof(GRoot)),
_GT(typeof(GLabel)),
_GT(typeof(GButton)),
_GT(typeof(GComboBox)),
_GT(typeof(GProgressBar)),
_GT(typeof(GSlider)),
_GT(typeof(PopupMenu)),
_GT(typeof(ScrollPane)),
_GT(typeof(Transition)),
_GT(typeof(UIPackage)),
_GT(typeof(Window)),
_GT(typeof(GObjectPool)),
_GT(typeof(Relations)),
_GT(typeof(RelationType)),
2、拷貝FairyGUI.lua到你的lua文件存放目錄。
二、使用
1、普通方法的偵聽和刪除偵聽
require ‘FairyGUI’
function OnClick() –也可以帶上事件參數(shù),OnClick(context)
print(‘you click’)
end
UIPackage.AddPackage(‘Demo’)
local view = UIPackage.CreateObject(‘Demo’, ‘DemoMain’)
GRoot.inst:AddChild(view)
view.onClick:Add(OnClick)
–view.onClick:Remove(OnClick)
2、類方法的偵聽和刪除偵聽
require ‘FairyGUI’
TestClass = class(‘TestClass’, {})
function TestClass:ctor()
UIPackage.AddPackage(‘Demo’)
self.view = UIPackage.CreateObject(‘Demo’, ‘DemoMain’)
GRoot.inst:AddChild(self.view)
self.view.onClick:Add(TestClass.OnClick, self)
–self.view.onClick:Remove(TestClass.OnClick, self)
end
function TestClass:OnClick() –也可以帶上事件參數(shù),TestClass:OnClick(context)
print(‘you click’)
end
TestClass.New()
3、如果要使用Tween,你可以直接使用GObject.TweenXXXX系列函數(shù),免除了Wrap DOTween的麻煩。