Unity3D熱更新LuaFramework入門實戰(3)——編寫Lua邏輯

為實現代碼熱更新,在Unity3D中使用lua,然而為此也需付出不少代價。其一,使代碼結構混亂(儘管可以優化),其二降低了運行速度,其三增加學習成本(還要多學一門語言)。為了熱更新,所有的邏輯都要用lua編寫,那麼怎樣用lua編寫遊戲邏輯呢?

By 羅培羽 (知乎 @羅培羽)

1、Lua的Update方法

第一篇「代碼熱更新」演示了用lua列印HelloWorld的方法,第二篇「資源熱更新」演示了載入坦克模型的方法。這一篇要把兩者結合起來,用lua實現「用鍵盤控制坦克移動」的功能。用Lua和用c#編寫的Unity3D程序大同小異,只需正確使用API即可,Lua語言的知識請參見《programing in lua》這本書。

1)Update方法

出於效率的考慮,tolua提供了名為UpdateBeat的對象,在LuaFramework中,只需給UpdateBeat添加回調函數,該函數便會每幀執行,相當於Monobehaviour的Update方法。Lua代碼如下所示:

function Main()tttttn UpdateBeat:Add(Update, self)nendn nfunction Update()ntLuaFramework.Util.Log("每幀執行一次");nendn

除了UpdateBeat,tolua還提供了LateUpdateBeat和FixedUpdateBeat,對應於Monobehaviour中的LateUpdate和FixedUpdate。

2)控制坦克

現在編寫「用鍵盤控制坦克移動」的lua代碼,載入坦克模型後,使用UpdateBeat註冊每幀執行的Update方法,然後在Update方法中調用UnityEngine.Input等API實現功能。代碼如下:

local go; --載入的坦克模型n n--主入口函數。從這裡開始lua邏輯nfunction Main()ntttttntLuaHelper = LuaFramework.LuaHelper;ntresMgr = LuaHelper.GetResManager();ntresMgr:LoadPrefab(tank, { TankPrefab }, OnLoadFinish);nendn n--載入完成後的回調--nfunction OnLoadFinish(objs)ntgo = UnityEngine.GameObject.Instantiate(objs[0]);ntLuaFramework.Util.Log("LoadFinish");ntntUpdateBeat:Add(Update, self)nendn n--每幀執行nfunction Update()ntLuaFramework.Util.Log("每幀執行");ntntlocal Input = UnityEngine.Input;ntlocal horizontal = Input.GetAxis("Horizontal");ntlocal verticla = Input.GetAxis("Vertical");ntntlocal x = go.transform.position.x + horizontalntlocal z = go.transform.position.z + verticlantgo.transform.position = Vector3.New(x,0,z)nendn

運行遊戲,即可用鍵盤的控制坦克移動。

圖:用鍵盤的控制坦克移動

2、自定義API

框架中提供了數十個可供lua調用的c#類,但這些往往不夠用,需要自己添加,本節將介紹添加自定義API的方法。

1)編寫c#類

例如,編寫TestLuaFun.類,它包含一個靜態方法Log,會列印出「《Unity3D網路遊戲實戰》是一本好書!」和「《手把手教你用c#製作rpg遊戲》也是一本好書!」兩行文本。

using UnityEngine;nusing System.Collections;n npublic class TestLuaFun n{ntpublic static void Log() nt{nttDebug.Log("《Unity3D網路遊戲實戰》是一本好書!");nttDebug.Log("《手把手教你用c#製作rpg遊戲》也是一本好書!");nt}n}n

2)修改CustomSetting

打開CustomSetting.cs,在customTypeList中添加一句「_GT(typeof(TestLuaFun))」。

圖:修改CustomSetting

3)生成wrap文件

點擊菜單欄的Lua→Clear wrap files和Lua→Generate All,重新生成wrap文件。由於剛剛在customTypeList添加了類,所以會生成TestLuaFun類的wrap文件TestLuaFunWrap.cs。

圖:生成wrap文件

打開TestLuaFunWrap.cs,可以看到TestLuaFun註冊了Log方法。關於static int Log(IntPtr L)的具體含義,請參見《programing in lua》中lua與c++交互的章節。

圖:TestLuaFunWrap

4)測試API

修改main.lua,調用TestLuaFun.Log() ,即可看到效果。

--主入口函數。從這裡開始lua邏輯nfunction Main()tttttntTestLuaFun.Log() nendn

圖:調用自定義API

3、原理

tolua實現了LuaInterface,拋開luaFramework,只需創建lua虛擬機,便能在c#中調用lua代碼,如下所示。

using UnityEngine;nusing System.Collections;nusing LuaInterface;n npublic class test : MonoBehaviourn{ntvoid Start () nt{ntt//初始化nttLuaState lua = new LuaState();nttLuaBinder.Bind(lua);ntt//lua代碼nttstring luaStr =nttt@" n print(hello tolua#, 廣告招租)nttttLuaFramework.Util.Log(HelloWorld);nttttTestLuaFun.Log() n ";ntt//執行lua腳本nttlua.DoString(luaStr);nt}n}n n

圖:創建lua虛擬機,執行lua代碼

實際上LuaFramework也是用了相似的方法,框架啟動後,會創建LuaManager、LuaLooper的實例。LuaManager創建lua虛擬機並調用Main.lua的Main方法,LuaLooper處理了UpdateBeat相關的事情。如下所示:

圖:LuaManager的啟動過程

筆者也是剛剛接觸LuaFramework不久,文章錯誤之處在所難免,請大家多加包涵。最後是廣告時間:

《仙劍5前傳之心愿》是筆者兩年前發起的一款仙劍同人遊戲,使用Unity3D製作,是市面上第一款能夠完成的3D仙劍同人遊戲。如今我們各自踏上遊戲開發一途,似乎要做點什麼以致敬國產經典之作,在追求商業成就的同時,勿忘初心。可以在pal5h.com下載該遊戲。

圖:《仙劍5前傳之心愿》截圖

推薦閱讀:

【Unity】工具類系列教程——對象池!
報名 | UWA優化日廈門站
塞爾達風之杖技術分析-水體渲染
淺談使用NGUI的界面架構(二)關於NData

TAG:Unity游戏引擎 | 游戏开发 | Lua编程 |