Unity3D熱更新LuaFramework入門實戰(4)——Lua組件
基於組件的編程模式是Unity3D的核心思想之一,然而使用純lua編程,基本就破壞了這一模式。那麼有沒有辦法做一些封裝,讓Lua腳本也能掛載到遊戲物體上,作為組件呢?
By 羅培羽
1、設計思想
在需要添加Lua組件的遊戲物體上添加一個LuaComponent組件,LuaComponent引用一個lua表,這個lua表包含lua組件的各種屬性以及Awake、Start等函數,由LuaComponent適時調用Lua表所包含的函數。
下面列舉lua組件的文件格式,它包含一個表(如Component),這個表包含property1 、property2 等屬性,包含Awake、Start等方法。表中必須包含用於派生對象的New方法,它會創建一個繼承自Component的表o,供LuaComponent調用。
Component= t--組件表n{ntproperty1 = 100,ntproperty2 = 「helloWorld」n}nnfunction Component:Awake() ntprint("TankCmp Awake name = "..self.name );nendnnfunction Component:Start() ntprint("TankCmp Start name = "..self.name );nEndnn--更多方法略nnfunction Component:New(obj) ntlocal o = {} n setmetatable(o, self) n self.__index = self ntreturn onend n
2、LuaComponent組件
LuaComponent主要有Get和Add兩個靜態方法,其中Get相當於UnityEngine中的GetComponent方法,Add相當於AddComponent方法,只不過這裡添加的是lua組件不是c#組件。每個LuaComponent擁有一個LuaTable(lua表)類型的變數table,它既引用上述的Component表。
Add方法使用AddComponent添加LuaComponent,調用參數中lua表的New方法,將其返回的表賦予table。
Get方法使用GetComponents獲取遊戲對象上的所有LuaComponent(一個遊戲對象可能包含多個lua組件,由參數table決定需要獲取哪一個),通過元表地址找到對應的LuaComponent,返回lua表。代碼如下:
using UnityEngine;nusing System.Collections;nusing LuaInterface; nusing LuaFramework;nnpublic class LuaComponent : MonoBehaviour n{nt//Lua表ntpublic LuaTable table;nnt//添加LUA組件 ntpublic static LuaTable Add(GameObject go, LuaTable tableClass) nt{ nttLuaFunction fun = tableClass.GetLuaFunction("New");nttif (fun == null)ntttreturn null;nnttobject[] rets = fun.Call (tableClass);nttif (rets.Length != 1)ntttreturn null;nnttLuaComponent cmp = go.AddComponent<LuaComponent>(); nttcmp.table = (LuaTable)rets[0];nttcmp.CallAwake ();nttreturn cmp.table;nt} nnt//獲取lua組件ntpublic static LuaTable Get(GameObject go,LuaTable table) nt{ nttLuaComponent[] cmps = go.GetComponents<LuaComponent>(); nttforeach (LuaComponent cmp in cmps) ntt{ntttstring mat1 = table.ToString();ntttstring mat2 = cmp.table.GetMetaTable().ToString();ntttif(mat1 == mat2)nttt{nttttreturn cmp.table;nttt}ntt}nttreturn null; nt} nt//刪除LUA組件的方法略,調用Destory()即可 nntvoid CallAwake () nt{nttLuaFunction fun = table.GetLuaFunction("Awake");nttif (fun != null)ntttfun.Call (table, gameObject);nt}nntvoid Start () nt{nttLuaFunction fun = table.GetLuaFunction("Start");nttif (fun != null)ntttfun.Call (table, gameObject);nt}nntvoid Update () nt{ntt//效率問題有待測試和優化ntt//可在lua中調用UpdateBeat替代nttLuaFunction fun = table.GetLuaFunction("Update");nttif (fun != null)ntttfun.Call (table, gameObject);nt}nntvoid OnCollisionEnter(Collision collisionInfo)nt{ntt//略nt}nn //更多函數略n}n
3、調試LuaCompomemt
現在編寫名為TankCmp的lua組件,測試LuaCompomemt的功能,TankCmp會在Awake、Start和Update列印出屬性name。TankCmp.lua的代碼如下:
TankCmp = n{nt--裡面可以放一些屬性ntHp = 100,ntatt = 50,ntname = "good tank",n}nnfunction TankCmp:Awake()ntprint("TankCmp Awake name = "..self.name );nendnnfunction TankCmp:Start()ntprint("TankCmp Start name = "..self.name );nendnnfunction TankCmp:Update()ntprint("TankCmp Update name = "..self.name );nendnn--創建對象nfunction TankCmp:New(obj)ntlocal o = {} n setmetatable(o, self) n self.__index = self ntreturn onend n
編寫Main.lua,給遊戲對象添加lua組件。
require "TankCmp"nn--主入口函數。從這裡開始lua邏輯nfunction Main()tn --組件1ttttntlocal go = UnityEngine.GameObject (go)ntlocal tankCmp1 = LuaComponent.Add(go,TankCmp)nttankCmp1.name = "Tank1"nt--組件2ntlocal go2 = UnityEngine.GameObject (go2)ntLuaComponent.Add(go2,TankCmp)ntlocal tankCmp2 = LuaComponent.Get(go2,TankCmp)nttankCmp2.name = "Tank2"nendn
運行遊戲,即可看到lua組件的運行結果:
圖:程序運行結果
圖:程序運行結果
4、坦克組件
下面代碼演示用lua組件實現「用鍵盤控制坦克移動」的功能,TankCmp.lua的代碼如下:
TankCmp = n{ntname = "good tank",n}nnfunction TankCmp:Update(gameObject)ntprint("TankCmp Update name = "..self.name );ntntlocal Input = UnityEngine.Input;ntlocal horizontal = Input.GetAxis("Horizontal");ntlocal verticla = Input.GetAxis("Vertical");ntntlocal x = gameObject.transform.position.x + horizontalntlocal z = gameObject.transform.position.z + verticlantgameObject.transform.position = Vector3.New(x,0,z)nendnn--創建對象nfunction TankCmp:New(obj)ntlocal o = {} n setmetatable(o, self) n self.__index = self ntreturn onend n
Main.lua先載入坦克模型,然後給他添加lua組件,代碼如下:
require "TankCmp"nn--主入口函數。從這裡開始lua邏輯nfunction Main()tttttntLuaHelper = LuaFramework.LuaHelper;ntresMgr = LuaHelper.GetResManager();ntresMgr:LoadPrefab(tank, { TankPrefab }, OnLoadFinish);nendnn--載入完成後的回調--nfunction OnLoadFinish(objs)ntgo = UnityEngine.GameObject.Instantiate(objs[0]);ntLuaComponent.Add(go,TankCmp)nendn
運行遊戲,即可用鍵盤的控制坦克移動。
圖:坦克組件運行結果
最後是廣告時間:
《Unity3D網路遊戲實戰》是筆者即將出版的一本Unity3D實戰類書籍。該書通過一個完整的多人坦克對戰實例,詳細介紹網路遊戲開發過程中涉及到的知識和技巧。書中還介紹了服務端框架、客戶端網路模塊、UI系統的架構等內容。相信透過本書,讀者能夠掌握Unity3D網路遊戲開發的大部分知識,也能夠從框架設計中了解商業遊戲的設計思路。
《手把手教你用C#製作RPG遊戲》(十二五全國高校數字遊戲設計精品教材)是筆者出版的第一本書,書中將一款完整單機RPG遊戲分解為角色、隊伍、地圖、NPC、界面系統、物品系統、技能系統、戰鬥系統、任務系統等模塊,一步步介紹每個模塊的實現方法,最後完成一款完整的遊戲。
圖:《手把手教你用C#製作RPG遊戲》項目截圖
推薦閱讀: