Cocos 插件教程:編寫帶擴展屬性插件的經驗分享
這兩天用cocos插件編寫了一個2d粒子控件。很明顯的感受是官方文檔不是很完善,那篇超級長的說明脈絡也不是很清晰,以至于我在此期間掉了不少坑走了不少彎路,不過這次cocos放出來的插件系統還是很靈活很強大的,從編輯到最終輸出都可以由我們自定義實現。這篇教程就來分享下我這兩天做擴展屬性過程中總結的經驗,探討在插件的編寫過程中的一些技巧,幫助下后來者。
一、如何開始?
可能大家之前看過這篇《Cocos Studio 擴展說明》(下稱《說明》):
http://cn.cocos2d-x.org/tutorial/show?id=2650
這說明篇幅之大之長,估計嚇退了不少小伙伴。鼓起勇氣讀下去的估計半路上也睡倒了一片。(我就看到睡著了幾次,信息量實在太大了,催眠神器啊有木有。。。)
實際插件的編寫并沒那么復雜,直接修改官方提供的sample工程即可。
打開sample工程。(sample工程的路徑請看《說明》第3點“示例工程位置”)
可以看到里邊有這么多文件:
說明:
ü 其中DataModel、Templates和ViewModel是官方的一個Custom控件的示例,Lua文件夾下也有類似的三個文件夾,這個是帶文本sprite插件的源碼。
ü Editor是屬性區自定義控件的例子。
ü PublishExtend是自定義導出數據格式的例子。
ü AddinConfig是插件的配置文件,配置當前插件所依賴的模塊,目前我們不需要改動。
復制一份插件工程,保留我們希望使用的例子來作為模版,其他文件刪除。
我期望寫個粒子插件,不需要自定義Editor和導出數據格式,因而我只保留ExtensionModel和Lua兩個文件夾,并將“Lua”重命名為“Particle”,如下所示:
然后根據我們的需要對剩下的文件做一些修改:
1. LuaObject.addin.xml文件
修改為T4模版生成的類。
2. ViewModel下的CustomParticleObject.cs文件
這個文件需要改三處
a.這四個屬性主要用于編輯器顯示控件的一些信息。還有CustomParticleObject繼承的類型也需要根據自己的需要修改。(具體看《說明》中的“視圖模型”部分)
b.創建插件時的默認名稱。
c.依賴的lua文件。即LuaScript文件夾下對應本插件的Lua文件。
3.DataModel的CustomParticleObjectData.cs修改如下兩處:
4. Lua文件夾下的CustomParticleObject.tt模板文件,修改繼承的對象類型和ViewModel類的類名。(具體看《說明》“Lua 代碼生成模板”部分)
OK,改完這些,我們就配置完一個插件工程了。接下來我們還需要在lua中完成對引擎的擴展,然后在編輯器中調用lua的接口。
PS:2.2.1升級至2.2.5之后,需要相應地升級插件工程,具體可看新版本示例工程中Addins/Addins.Sample/Lua/修改記錄.txt
二、 編寫對應的Lua文件
這一步主要是將我們的接口準備好,給上邊配置的C#工程調用。
首先是必須做的四件事:
1.在文件的***返回一個table給插件工程,此后插件工程會在這個table上找需要的接口。這里我們稱這個table為“container”
2.為“container”添加CreateCustomNode的工廠函數,創建一個我們擴展的Cocos2d-x對象并返回。
3.為“container”添加一個GetBaseType函數,返回我們插件的基礎類型。(之后我們的插件也會有這個基礎類型的編輯接口。)
4.把編寫出來的文件放到cocos文檔路徑的Addins/LuaScript下
然后在1所述的table上添加一些屬性接口來跟插件工程進行數據交換,可交換的數據只能是如下這些數據類型,且一次只能交換一個數據:
Bool
Int
String
Double
Float
Color
ResourceData
PS:lua下沒有區分Float、Double和Int,這些都用double來承載。
技巧:
1.插件工程在table上查找字段的方式不是用rawget方式,因此元表還是可用的,我們可以給table設置__index元表,重定向到我們的所擴展的2d-x對象,某些我們所擴展的對象已經有的簡單接口用元表定位即可,不需要在table中再寫一次,減少一點工作量。
2.如果這個lua文件出錯了,cocos不會給什么有用的調試信息。我們先在一個2d-lua工程里邊調試,直到所有接口都正常工作后再放到cocos中,這樣能節約不少時間。
3.這個文件跟最終導出的數據不一定有關聯。
三、 在插件工程中添加與lua層交換數據的接口
主要是給視圖模型(ViewModel文件夾下那個對象)編寫一些property,每編寫一個property編輯器就會在屬性區生成一個屬性控件。然后就可以用這些屬性控件來進行可視化編輯。
與lua的通訊需要通過LuaValueConverter來調用Lua層的接口,進行數據交換。
一個基本的property大概是這樣的:
[UndoPropertyAttribute]
[DisplayName("TangentialAccel")]
[Category("Group_Feature")]
[PropertyOrder(-99)]
[Browsable(true)]
public float TangentialAccel
{
get
{
return luaValueConverter.GetFloatValue("getTangentialAccel");
}
set
{
luaValueConverter.SetFloatValue("setTangentialAccel",value);
this.RaisePropertyChanged(() => this.TangentialAccel);
}
}
首先是幾個用中括號包著的attribute、當前property的聲明然后是getter、setter定義。Attribute值的作用可以看看《說明》的“屬性區擴展”一節。
其次還有setValue函數。這個函數在進行克隆操作時發揮作用。將上述寫的property賦值給傳進來的cObject對象相對應的property即可。
技巧:
1.如果有比較多的屬性的話,可以先寫同一類型的擴展屬性,調試到可用后復制黏貼,修改名字。
2.可以用Cocos Studio.Basic.LogConfig.Output.Info(String )在C#插件工程中輸出錯誤信息。
3.調試時使用VS的“調試”-“附加到進程”,附加到Cocos Studio主進程進行調試,C#代碼出錯時,VS會幫你指出出錯的位置并且有詳細的調試信息。所有導致崩潰的錯誤一般都能夠定位到。
4.目前lua下沒有輸出錯誤信息的接口,少量的調試信息可以用一個text控件放在創建的節點上做輸出。Lua下socket和io模塊還能夠使用,我們可以利用這兩個模塊來輸出調試信息,我使用的是socket,大家可以參考下我的源碼。cocos的研發同學表示會盡快提供log接口,到時就沒那么麻煩了。
四、 編輯DataModel
即CustomParticleObjectData.cs文件,以property的方式聲明下各個需要被保存到csd文件的性質,前面寫上[ItemProperty] [JsonProperty]。這樣這些數據就會被保存到csd文件當中了,我們關掉編輯器再次打開,編輯過的數據就不會丟失了。生成T4模板的時候,模板里邊引用的值也是從這里來的。
注意顏色類型的性質要用ColorData聲明(是的我被坑過)。這里可能出錯的點是數據類型寫錯,現象是不能保存也不能導出。
五、 代碼生成模板
即Lua文件夾下的CustomParticleObject.tt模板文件。功能是將編輯器編輯出來的值按特定模板輸出出來。
技巧:
如果你看過我的lua文件和T4模板的話,你會發現二者之間毫無關聯。我的lua文件中的CreateCustomNode是創建了一個node對象然后再建一個particle對象做為node的子對象。這樣做的目的是為了能夠實現更換粒子模板的效果(更換粒子模板需要重新生成粒子對象)。
其實T4就是根據模板將值填寫到字符串中,最終保存到文件里,愿意的話,生成C++代碼都沒問題。