Cocos Creator學(xué)習(xí)筆記
一直聽說cocos做2d很好,但是從未嘗試過.公司打算從egret轉(zhuǎn)型到cocos creator,所以我花了兩周時(shí)間,兩個(gè)引擎都學(xué)習(xí)嘗試了一下,并且完成一個(gè)小項(xiàng)目的開發(fā).
下面我會(huì)簡單講講在學(xué)習(xí)和開發(fā)過程中用到的知識(shí)點(diǎn)和踩過的坑,并且從頭開始使用fgui和cocos開發(fā)一個(gè)小游戲《圍住神經(jīng)貓》
Egret的學(xué)習(xí)筆記可以參考我的這篇文章Egret《圍住神經(jīng)貓》筆記
0.踩過的坑
剛剛學(xué)完egret,我就馬不停蹄的開始學(xué)習(xí)cocos creator(以下簡稱cocos).egret是一個(gè)開發(fā)頁游的引擎,用起來更像寫前端,加上做的這個(gè)項(xiàng)目《圍住神經(jīng)貓》是一個(gè)比較簡單的游戲,所以游戲間的邏輯完全使用事件串起來,一點(diǎn)沒用到生命周期回調(diào),也沒有基于場(chǎng)景和節(jié)點(diǎn)的開發(fā)思想在里面,所以完全不能和之前學(xué)的unity聯(lián)系起來.
cocos其實(shí)和unity在思想上是很像的(unity的GameObject就對(duì)應(yīng)cocos的Node),但是我最開始一直用egret的開發(fā)思維帶入cocos,結(jié)果就是非常痛苦,寫出來的東西不管怎么調(diào)都完全跑不通,其實(shí)是因?yàn)闆]有用基于節(jié)點(diǎn)的思維去做開發(fā).
說到底還是沒有學(xué)扎實(shí),之前用unity一直是靜態(tài)場(chǎng)景拖拽GameObject來綁定和獲取組件,沒有嘗試過在代碼中進(jìn)行這些操作,這樣做其實(shí)是不利于理解引擎底層邏輯的.現(xiàn)在我已經(jīng)能夠?qū)煞N思維融會(huì)貫通運(yùn)用在cocos中了.
1.知識(shí)點(diǎn)
1.1cocos家族
cocos和Unity不同,它有不同的引擎分支,產(chǎn)品之間差異很大,現(xiàn)在用的最多的應(yīng)該是Cocos-2dx和Cocos Creator,我學(xué)習(xí)的是Cocos Creator,以下簡稱cocos代指的就是它.
1.2常駐節(jié)點(diǎn)
開發(fā)時(shí)希望有一些全局的數(shù)據(jù)能夠被任何模塊訪問到,但是一般的場(chǎng)景切換會(huì)銷毀原先的場(chǎng)景導(dǎo)致數(shù)據(jù)被清除,如果不銷毀場(chǎng)景,占用資源就太多了.有一個(gè)方法是選定某個(gè)節(jié)點(diǎn),將其作為常駐節(jié)點(diǎn),這樣,在一個(gè)場(chǎng)景設(shè)置的節(jié)點(diǎn),在其他場(chǎng)景也可以訪問到,并且不會(huì)被清除,也無需重新構(gòu)造.
在Unity中,有一個(gè)方法是使用PlayerPref做數(shù)據(jù)持久化,這個(gè)方法會(huì)把數(shù)據(jù)持久化到注冊(cè)表中.不過這已經(jīng)超出了"全局?jǐn)?shù)據(jù)"的需求
以下是cocos官方文檔中的內(nèi)容
場(chǎng)景切換時(shí),所有界面都會(huì)被銷毀。如果不想被銷毀,需要?jiǎng)?chuàng)建出界面后,把根節(jié)點(diǎn)設(shè)置為常駐,并且切換場(chǎng)景前,確保關(guān)閉界面。
? ?cc.game.addPersistNode(view.node);
1.3FairyGUI
簡稱fgui,是一套gui設(shè)計(jì)解決方案,為了盡可能實(shí)現(xiàn)gui和代碼分離,方便設(shè)計(jì)師使用而出現(xiàn)的工具.我沒有用過cocos原生的ui,只說fgui,我覺得很難用,它似乎對(duì)Unity支持的特別好,但是現(xiàn)在Unity原生的UGUI已經(jīng)做的很好用了,又是人家官方的前途一片光明,為什么還要用fgui呢.但是cocos的gui顯然做的一般,所以fgui還是要用.
一句話總結(jié)fgui的工作流:繪制gui組件->打包成各種引擎可以使用的包(在這里是cocos)->在引擎中使用代碼加載和獲取組件. 具體怎么繪制要看fgui的編輯器教程,教你每個(gè)組件干什么有什么用,如何在引擎中使用繪制的組件喲啊看fgui的sdk教程,會(huì)教你fgui給各個(gè)引擎的API,但是很少,也有一部分具體組件的API是在編輯器教程的.但是它的教程寫的很一般,對(duì)于非Unity的引擎,有很多東西都沒有講,所以用起來比較難受
加載fgui組件的核心api是fgui.UIPackage.createObject(packageName:string,objectName:string),一般要用到的資源會(huì)在fgui中做成組件,加載會(huì)直接加載組件,所以方法后面一般會(huì)加上.asCom.這個(gè)方法似乎是異步的,注意調(diào)用順序,否則可能會(huì)獲取不到當(dāng)前的組件.
1.4事件系統(tǒng)
cocos的事件系統(tǒng)是基于節(jié)點(diǎn)的,而fgui的事件系統(tǒng)又是基于cocos的,所以二者在邏輯上相通,看看官方文檔是怎么說的吧:
FairyGUI直接使用了Creator的事件系統(tǒng),所以GObject.on/off其實(shí)是通過GObject.node.on/off實(shí)現(xiàn)的,也就是可以通過GObject.node進(jìn)行任何事件的操作,包括自定義的事件。在事件回調(diào)中,cc.Event中的currentTarget反映的是這個(gè)事件是由哪個(gè)node派發(fā)的,如果要獲得這個(gè)node對(duì)應(yīng)哪個(gè)GObject,可以用這樣的方法:
? ?aObject.on(someEventName, this.onHandle, this); ? ?onHandle(evt:cc.Event) { ? ? ? ?cc.log(evt.currentTarget); //node對(duì)象 ? ? ? ?cc.log(fgui.GObject.cast(evt.currentTarget)); //gobject對(duì)象 ? ?}
除了基于節(jié)點(diǎn)處理事件以外,cocos和fgui的事件系統(tǒng)和常規(guī)的事件系統(tǒng)沒有什么區(qū)別:發(fā)送事件是一個(gè)向上級(jí)拋出信息的過程,在父級(jí)對(duì)子物體加監(jiān)聽可以實(shí)現(xiàn)事件的傳遞.想要傳遞事件,我們?cè)谝粋€(gè)對(duì)象內(nèi)部發(fā)送事件,然后在它的父對(duì)象中通過引用對(duì)子對(duì)象加監(jiān)聽,這樣父對(duì)象就可以根據(jù)子對(duì)象的事件來處理邏輯,如果要多級(jí)傳遞,那么就在父對(duì)象的事件處理邏輯中發(fā)送消息給祖父對(duì)象,以此類推.
1.5 fgui.List
之前學(xué)習(xí)egret的時(shí)候已經(jīng)學(xué)習(xí)了eui.list,當(dāng)時(shí)是自己封裝的呈示單元,這次想試一下在fgui編輯器界面指定現(xiàn)有的組件作為呈示單元,結(jié)果發(fā)現(xiàn)完全不能移動(dòng)單元組件,根本就做不了六邊形網(wǎng)格.嘗試將組件的圖片移動(dòng)位置來實(shí)現(xiàn)偏移,結(jié)果list監(jiān)聽點(diǎn)擊的判定還在單元組件上,點(diǎn)擊圖片不等于點(diǎn)擊組件,這下更寄了.無奈,還是重新封裝了呈示單元.然后使用addChild一個(gè)個(gè)添加節(jié)點(diǎn).
不過驚喜的是fgui.List的監(jiān)聽居然是冒泡事件,可以呈示單元發(fā)送的事件可以穿透封裝類直接到List上面,這樣就不用單獨(dú)加監(jiān)聽和重寫事件了
總結(jié)下來兩個(gè)要點(diǎn):list的監(jiān)聽是冒泡事件,list的呈示單元受限于布局,不能調(diào)整位置
2.從0開始的cocos小游戲開發(fā)
2.0原先的基礎(chǔ)
本次實(shí)戰(zhàn)是將原先寫的Egret小游戲項(xiàng)目《圍住神經(jīng)貓》移植到cocos creator上.cocos和Egret在開發(fā)邏輯上有很多不同,所以代碼也有了架構(gòu)上的更改和優(yōu)化,比如:
腳本類基本上全部繼承cc.component,基于節(jié)點(diǎn)進(jìn)行開發(fā)
使用多場(chǎng)景,設(shè)計(jì)場(chǎng)景切換的邏輯
使用一個(gè)Resource_Loader類管理資源和場(chǎng)景,實(shí)現(xiàn)動(dòng)態(tài)加載
因?yàn)橐恢痹谶M(jìn)步,編碼規(guī)范上有了進(jìn)步,代碼質(zhì)量提升,比如說使用公司要求的縮進(jìn)規(guī)范,整合重復(fù)且僅僅有細(xì)微差別的代碼,拆解邏輯結(jié)構(gòu),使得代碼邏輯更合理
原項(xiàng)目文檔:Egret學(xué)習(xí)筆記
2.1FGUI設(shè)計(jì)UI組件
打開fgui,新建項(xiàng)目,項(xiàng)目名稱位置隨意,fgui的項(xiàng)目和cocos項(xiàng)目是完全獨(dú)立的.
把你的素材拖進(jìn)fgui編輯器,新建若干個(gè)需要的組件,開始設(shè)計(jì).記得將需要被代碼獲取的組件和子組件規(guī)范命名,方便一會(huì)綁定.

2.2 導(dǎo)出UI組件到cocos
在左邊資源欄將需要使用的組件設(shè)置為導(dǎo)出,點(diǎn)擊發(fā)布設(shè)置(就是三個(gè)小飛機(jī)最右邊那個(gè))設(shè)置導(dǎo)出的信息地址,一般來說我們會(huì)把包放到cocos目錄的asset/resources地址下,因?yàn)閞esources這個(gè)文件夾是可以被cocos自動(dòng)獲取的.設(shè)置完成后點(diǎn)擊導(dǎo)出,就能在cocos下面看到一個(gè)文件夾里放著你的素材,素材以圖集的形式保存,通過fgui提供的API加載特定組件,這樣可以減少drawcall

2.3 獲取組件
創(chuàng)建出幾個(gè)主要場(chǎng)景的管理類,在類中定義組件,并獲取組件,這里以游戲勝利的對(duì)話框?yàn)槔?
這個(gè)類中包含對(duì)話框組件canvas_success和它其中的按鈕以及文本

初始化時(shí),加載對(duì)應(yīng)的組件.
注意,這里能直接使用createObject是因?yàn)橹耙呀?jīng)加載包了,加載包的代碼是
fgui.UIPackage.loadPackage("Package/MainPackage", function(err) {
});//花括號(hào)中寫回調(diào)函數(shù)

2.4 編寫UI事件
Resource_Loader類不僅負(fù)責(zé)加載用到的幾個(gè)場(chǎng)景類,還負(fù)責(zé)管理它們,場(chǎng)景動(dòng)態(tài)加載,至于加載哪些場(chǎng)景,數(shù)據(jù)類中的場(chǎng)景名稱會(huì)提供
設(shè)置幾個(gè)Prefab屬性值,這些Prefab是掛載了各自場(chǎng)景管理腳本的場(chǎng)景管理器節(jié)點(diǎn)

初始化時(shí),加載對(duì)應(yīng)節(jié)點(diǎn),給對(duì)應(yīng)的節(jié)點(diǎn)添加監(jiān)聽

提供一些UI邏輯處理的方法

在各自的場(chǎng)景管理類中添加發(fā)送事件的方法,并且對(duì)各自的子UI組件加監(jiān)聽,就像上面的Scene_Success一樣
2.5 使用fgui.GList實(shí)現(xiàn)六邊形點(diǎn)陣
用Game_Node封裝呈示單元,構(gòu)造Game_Node的時(shí)候綁定呈示單元
提供一些屬性和方法用于邏輯交互

用一個(gè)靜態(tài)類管理這些數(shù)據(jù)

在游戲界面管理器中,使用addChild方法直接向List中添加這些節(jié)點(diǎn),更改Game_Node中組件的位置:

給List添加監(jiān)聽,注意,這些監(jiān)聽是可以冒泡的,所以他們能直接監(jiān)聽Game_Node.loader

2.6游戲邏輯代碼
主要在Scene_Game中
下面是刷新狀態(tài)的代碼,由點(diǎn)陣中的點(diǎn)被點(diǎn)擊后發(fā)出事件來觸發(fā),具體包括了貓的邏輯和數(shù)據(jù)變化的邏輯,和我在egret項(xiàng)目中的很像

2.7貓邏輯代碼
不贅述了,和egret項(xiàng)目很像
2.8資源加載和管理類
預(yù)置幾個(gè)預(yù)制體的位置,在cocos里面掛載這些節(jié)點(diǎn),通過實(shí)例化的方式獲取節(jié)點(diǎn)和場(chǎng)景腳本



2.9跨場(chǎng)景全局?jǐn)?shù)據(jù)類
記錄各種用得到的靜態(tài)數(shù)據(jù),設(shè)置為全局節(jié)點(diǎn)使得所有場(chǎng)景中都可以訪問而不需要重復(fù)設(shè)置.

最終效果不再展示,和egret版本的表現(xiàn)是一樣的.