在上篇文章 Unity3D熱更新之LuaFramework篇[01]--從零開始 中,咱們瞭解了怎麼得到一個可用的LuaFramework框架。html
本篇將我會先介紹一下如何配置Lua開發環境,而後分析在此框架中加載面板的流程,以及如何建立本身的面板。git
有一點要說明的是,使用此種方式(ToLua+LuaFramework)作熱更新,則意味着你的大部分邏輯都須要改用Lua語言來編寫。github
所以,開發前得先得配置好Lua開發環境。畢竟,工欲善其事,必先利其器。windows
環境配置大概分如下三個步驟:框架
1.安裝IntelliJ IDEA Community Edition 2018.2.4 x64
官網地址 http://www.jetbrains.com/idea/download/#section=windows編輯器
直接下載便可,下載 Community 版本,也就是社區版,免費的ide
2.下載Lua For Windows
https://github.com/rjpcomputing/luaforwindows/releases函數
下載最新的就行,而後安裝。post
3.安裝emmylua插件
安裝插件有2種方法,能夠直接搜插件庫安裝,或者下載好插件後本地加載。學習
以上安裝步驟均來自:三頁菌 的文章 最好用的lua編輯器--------emmylua使用匯總。
其文章極其詳細的介紹瞭如何搭建並配置一個好用的Lua開發環境,請自行參考。
在上一篇文章最後,咱們運行框架,最終顯示了一個Lua腳本動態建立的面板,即PromptPanel,如圖2-1所示。
圖2-1
翻看框架的目錄結構,會在Assets/LuaFrame/Examples/Builds/Prompt目錄找到兩個預製體,PromptPanel和PromptItem,也就是這個面板的主體和獸人頭像,如圖2-2所示。
圖2-2
用上一節中安裝的IntelliJ IDEA打開工程目錄,在Controller目錄和View目錄會找到與PromptPanel密切相關的兩個文件PromptCtrl.lua、PromptPanel.lua,如圖2-3所示
圖2-3
由目錄名稱可知,此框架採用了一種MVC結構,用以對代碼功能作區分。XxxPanel負責頁面顯示邏輯,XxxCtrl負責事件處理,示例沒有給出明顯的Model層,讀者能夠根據自身項目酌情添加。
繼續查看框架代碼,會在Logic/Game.lua中找到遊戲的入口:Game.OnInitOK函數,見圖2-4。
圖2-4
在這個函數中,有3個重要邏輯:
一、初始化View
二、初始化Ctrl
三、啓動Ctrl
一、初始化View
初始化View就是調用InitViewPanels這個函數,InitViewPanels函數用於加載View目錄下定義的XxxPanel,在Game.lua的17行中能夠看到定義。
function Game.InitViewPanels() for i = 1, #PanelNames do require ("View/"..tostring(PanelNames[i])) end endPanelName則是在LuaFramwwork/Lua/Common/define.lua的第7行中定義的,對應面板的名稱。
PanelNames = { "PromptPanel", "MessagePanel", }
二、初始化Ctrl
初始化Ctrl是指CtrlManager.Init();這句,能夠在LuaFramwwork/Lua/Logic/CtrlManager.lua第9行中看到相關定義。這個函數中經過調用New函數建立了Ctrl的實例。
function CtrlManager.Init() logWarn("CtrlManager.Init----->>>"); ctrlList[CtrlNames.Prompt] = PromptCtrl.New(); ctrlList[CtrlNames.Message] = MessageCtrl.New(); return this; end
三、啓動Ctrl
啓動就是根據CtrlNames找到對應的Ctrl的實例,而後調用其Awake方法,見代碼:
local ctrl = CtrlManager.GetCtrl(CtrlNames.Prompt); if ctrl ~= nil and AppConst.ExampleMode == 1 then ctrl:Awake(); end
以上都是推測,
爲了驗證猜想的對不對,我把CtrlManager.GetCtrl(CtrlNames.Prompt)這一句改成CtrlManager.GetCtrl(CtrlNames.Message),若是此次加載出來的是MessagePanel,則說明上述過程推斷正確。
....
改完後運行,發現加載的仍是PromptPanel,難道確實是找錯地方了?
別急,這裏還涉及另外一個概念。
在熱更框架中,程序運行的並非咱們在LuaFramework/lua目錄下編寫的代碼,而是在Assets/StreamingAssets目錄下的打包後的代碼,見圖2-5。
圖2-5
那麼有什麼辦法讓咱們剛剛改的代碼生效呢?
思路有兩個:
- 將們的寫的代碼打包到StreamAssets中;
- 讓程序直接運行打包前的代碼;
思路1的操做方法是:執行LuaFramework菜單下的Build XXX Resources菜單(見圖2-6),由於我如今的程序是運行在Windows平臺,因此選擇Build Windows Resource。
圖2-6
點擊菜單,等待從新打包完成。打包結束後,能看到整個StreamingAssets目錄中的內容都更新了,在裏邊能夠找到message和prompt相關的資源,見圖2-7。
圖2-7
從新運行後,獲得了想的結果,程序直接加載了MessagePanel面板,見圖2-8。
圖2-8
由此印證咱們對整個面板流程的加載的推測分析。
關於思路2讓程序直接運行打包前的代碼,只須要關閉Lua的AssetBundle模式就行了。
找到LuaFramework/Scripts/ConstDefine/AppConst.cs文件,將LuaBundleMode = true;改成
LuaBundleMode = false;便可,見圖2-8,圖中是改過以後的。
圖2-8
LuaBundleMode 改成false以後,Lua代碼修改後就無需從新Build xxx Resources就能直接看到效果。
儘管思路1和思路2是二選一便可的,但爲方便後邊的示例,這裏要統一修改成false。
在上一步的分析中,咱們得知建立一個面板須要先初始化View,再實例化Ctrl,而後調用Ctrl的Awake。這些都是代碼層面的,前提還有一個,咱們須要一個XxxPanel預製體。
總結一下,若是要建立一個咱們本身的面板,則須要以下步驟:
一、建立一個XxxPanel預製體
二、建立對應的XxxView
三、建立對應的XxxCtrl
四、添加CtrlNames及PanelNames
五、加載XxxCtrl
下面我將以FirstPanel爲例進行演示。
一、建立FirstPanel預製體。
在Hierarchy面板中建立一個FirstPanel,並在LuaFramework目錄下新建CustomPrj/FirstTest目錄,將FirstPanel拖到此作成預製體,見圖3-1。
圖3-1
而後刪掉Hierarchy面板中的FirstPanel,由於後面咱們會動態加載它。
二、建立FirstView.lua腳本。
在Lua/View目錄下建立一個FirstView的lua腳本,腳本結構參照MessageView編寫,以下:
View Codelocal transform; local gameObject; FirstPanel = {}; local this = FirstPanel; --啓動事件-- function FirstPanel.Awake(obj) gameObject = obj; transform = obj.transform; this.InitPanel(); logWarn("Awake lua--->>"..gameObject.name); end --初始化面板-- function FirstPanel.InitPanel() --這句要註釋掉,由於咱們的FirstPanel中沒有按鈕 --this.btnClose = transform:FindChild("Button").gameObject; end --單擊事件-- function FirstPanel.OnDestroy() logWarn("OnDestroy---->>>"); end
注:lua腳本的建立方法是在IDEA中,選中目錄,右鍵->New->Lua File。
三、建立FirstCtrl.lua腳本。
在Lua/Controller目錄下建立一個FirsCtrl的lua腳本,腳本結構參照MessagCtrl編寫,以下:
View Code1 FirstCtrl = {}; 2 local this = FirstCtrl; 3 4 local message; 5 local transform; 6 local gameObject; 7 8 --構建函數-- 9 function FirstCtrl.New() 10 logWarn("FirstCtrl.New--->>"); 11 return this; 12 end 13 14 function FirstCtrl.Awake() 15 logWarn("FirstCtrl.Awake--->>"); 16 panelMgr:CreatePanel('First', this.OnCreate); 17 end 18 19 --啓動事件-- 20 function FirstCtrl.OnCreate(obj) 21 gameObject = obj; 22 23 message = gameObject:GetComponent('LuaBehaviour'); 24 25 --這句要註釋掉,由於咱們的FirstPanel中沒有按鈕 26 --message:AddClick(MessagePanel.btnClose, this.OnClick); 27 28 logWarn("Start lua--->>"..gameObject.name); 29 end 30 31 --單擊事件-- 32 function FirstCtrl.OnClick(go) 33 destroy(gameObject); 34 end 35 36 --關閉事件-- 37 function FirstCtrl.Close() 38 panelMgr:ClosePanel(CtrlNames.Message); 39 end
四、添加CtrlNames及PanelNames
在Lua/Common找到define.lua,在CtrlNames中添加 First = "FirstCtrl",在PanelNames中添加"FirstPanel",以下:
CtrlNames = { Prompt = "PromptCtrl", Message = "MessageCtrl", First = "FirstCtrl" } PanelNames = { "PromptPanel", "MessagePanel", "FirstPanel" }
五、加載FirstCtrl
在Lua/Logic/Game.lua文件的Game.OnInitOK函數中,將CtrlManager.GetCtrl()的參數修改成咱們剛剛添加的CtrlNames.First,以下所示:
CtrlManager.Init(); local ctrl = CtrlManager.GetCtrl(CtrlNames.First); if ctrl ~= nil and AppConst.ExampleMode == 1 then ctrl:Awake(); end
保存代碼並運行
..............
嗯,什麼都沒加載出來。
好吧,我得認可,在學習這個框架的過程當中,每走一步都是坑。
我就是在艱難的趟過這些坑來以後,才以爲有必要將這個過程記錄下來,纔有了這一系列文章,但願對後來人有所幫助。
.............
爲何咱們本身的建立的面板沒有加載呢?
查看日誌發現,在"LuaFramework InitOK--->>>"日誌輸出以前,PromptCtrl.New和MessageCtrl.New都被調用了一次,而咱們新加的FirstCtrl卻沒有,見圖3-2。
圖3-2
應該是咱們某些地方少加了調用。
查找後發現,確實有這樣一個地方。在Lua/Logic/CtrlManager.lua腳本的Init方法,對全部Ctrl的New方法進行了調用。
咱們添加對FirstCtrl.New的調用,以下:
function CtrlManager.Init() logWarn("CtrlManager.Init----->>>"); ctrlList[CtrlNames.Prompt] = PromptCtrl.New(); ctrlList[CtrlNames.Message] = MessageCtrl.New(); ctrlList[CtrlNames.First] = FirstCtrl.New(); return this; end(其實第二節中咱們發現了這個地方,本節中忘了將本身的代碼加進去)
而後再運行
.....
報錯了,說咱們的FirstCtrl是一個nil value, 見圖3-3
圖3-3
經查,是在CtrlManager中,咱們沒有加載對應的腳本,見圖3-4(圖中是已添加以後的)
圖3-4
再次運行
出現了更多的錯誤,見圖3-5
圖3-5
......
有沒有想崩潰的感受,唉,我當初就是這麼一步步過來的。
此次的錯誤是缺乏first.unity3d.
這裏的緣由是,咱們以前剛把Lua代碼AssetBundle模式關掉(設置爲false),lua代碼不用AssetBundle模式了,但咱們的資源(FirstPanel預製體)還 是使用的AssetBundle模式。
而且資源的AssetBundle模式好像沒法關閉,所以須要對FirstPanel預製體進行打包操做。
操做以下:
一、找到LuaFramework/Editor/Packager.cs文件中的HandleExampleBundle方法(約160行左右),添加對FirstPanel預製體打包的代碼,包名爲"first",以下所示:
/// <summary> /// 處理框架實例包 /// </summary> static void HandleExampleBundle() { string resPath = AppDataPath + "/" + AppConst.AssetDir + "/"; if (!Directory.Exists(resPath)) Directory.CreateDirectory(resPath); AddBuildMap("prompt" + AppConst.ExtName, "*.prefab", "Assets/LuaFramework/Examples/Builds/Prompt"); AddBuildMap("message" + AppConst.ExtName, "*.prefab", "Assets/LuaFramework/Examples/Builds/Message"); //打包咱們新加的FirstPanel預製體 AddBuildMap("first" + AppConst.ExtName, "*.prefab", "Assets/LuaFramework/CustomPrj/FirstTest"); AddBuildMap("prompt_asset" + AppConst.ExtName, "*.png", "Assets/LuaFramework/Examples/Textures/Prompt"); AddBuildMap("shared_asset" + AppConst.ExtName, "*.png", "Assets/LuaFramework/Examples/Textures/Shared"); }
二、執行unity編輯器上方LuaFramework菜單中的Build Windows Resources菜單項,進行打包操做。打包完成後,能夠在StreamingAssets目錄中看到first.unity3d文件。見圖3-6
圖3-6
再次運行,
此次終於獲得了咱們想要的結果,咱們本身建立的面板FirstPanel,就這麼加載出來了。
見圖3-7
圖3-7
真是太不容易了!
如今,將咱們改錯的通過都加入到完整的步驟中,那麼,加載一個咱們本身建立的面板的完整步驟以下:
一、建立一個XxxPanel預製體
二、建立對應的XxxView
三、建立對應的XxxCtrl
四、添加CtrlNames及PanelNames
五、在CtrlManager中加入對XxxCtrl.New的調用,並在頭部require "XxxCtrl"
六、在Packager.cs文件中對XxxPanel預製體進行打包
七、在Game.lua加載XxxCtrl
後續寫模塊的時候都會按這個流程來。
在本篇文章的第二節的寫做過程當中,爲何我會用推測並驗證的寫法,而不是直接給出一個正確結論?第三節中,我爲何沒有直接給出正確的操做步驟,而是邊走邊改錯?
由於我但願本文能如實還原我學LuaFramework的過程,記錄每個問題的發生條件,以及我解決問題的思路。
下一篇文章將會介紹如何加載非XXXPanel的預製體以及按鈕事件處理。