ToLua SimpleFramework NGUI/UGUI基礎知識[2]
原文位址:http://doc.ulua.org/default.asp?cateID=4
視訊位址:http://pan.baidu.com/s/1gd8fG4N
看完基礎知識1,不知道是否已經對熱更有了新的概念,如果有的話,我們繼續說下,SimpleFramework怎麼來做熱更的具體步驟。
(1)第一步打包資源到StreaminAssets目錄,為啥要打包到這個目錄下呢?懂U3D遊戲開發的都知道,這個目錄會随着Unity最終生成APK/IPA的包原目錄打包出去,我們的遊戲用戶端架構可以通過代碼讀取到裡面的資源,并且把裡面的資源複制到玩家的手機本地存儲裡面,這叫做解包。
那怎麼打包呢?打包的資源分為素材資源與代碼資源,這兩部分的打包,架構都內建了,你可以直接修改裡面的腳本邏輯适應自己的遊戲項目,我們打開ulua/Editor/Packager.cs打包腳本。這裡面根據不同的平台打包相應的資源。
[MenuItem("Game/Build iPhone Resource", false, 11)]
public static void BuildiPhoneResource() {
BuildTarget target;
#if UNITY_5
target = BuildTarget.iOS;
#else
target = BuildTarget.iPhone;
#endif
BuildAssetResource(target, false);
}
[MenuItem("Game/Build Android Resource", false, 12)]
public static void BuildAndroidResource() {
BuildAssetResource(BuildTarget.Android, true);
}
[MenuItem("Game/Build Windows Resource", false, 13)]
public static void BuildWindowsResource() {
BuildAssetResource(BuildTarget.StandaloneWindows, true);
}
重要的函數是下面這個,它打包了架構自帶例子的素材檔案後,繼續處理Lua代碼檔案的打包。
public static void BuildAssetResource(BuildTarget target, bool isWin) {
if (AppConst.ExampleMode) {
HandleExampleBundle(target);
}
HandleLuaFile(isWin);
AssetDatabase.Refresh();
}
HandleExampleBundle函數就是将Examples/Builds下面的素材統一按照Unity的規則進行打包成assetbundle檔案。沒什麼好說的。
我們主要是看HandleLuaFile函數的操作流程。
(1)在StreamingAssets目錄下面建立lua目錄,用于存放編碼後的lua檔案。
(2)周遊Lua目錄下面所有的lua檔案,并且根據目錄結建構立相應目錄樹。
(3)如果AppConst.LuaEncode 設定了編碼開關,就啟動編碼操作,否則直接複制源碼過去。
(4)然後将前面的圖檔素材assetbundle跟相對應的lua檔案目錄,統一周遊計算出MD5/CRC,生成到files.txt裡面。
這個代碼就做了這幾件事情,唯一需要展開介紹的隻有怎麼編碼Lua檔案了吧。這個函數其實并不長,
他就是根據相應的平台配置其編碼器,編碼器存放的路徑也就是前面工程外的LuaEncoder的目錄,拼湊出它的路徑後,我們開始拼湊其編碼的參數指令行,
需要注意的是luajit跟luavm的編碼指令行不同:
luajit的:luajit.exe -b srcfile outfile
luavm的:luac -o outfile srcfile
指令行的格式其實都很簡潔,然後我們啟動C#的調用外部shell程式的代碼,調用他們來編碼出2進制檔案即可。那最後統一計算MD5的檔案就變成了編碼的2進制的值。
//------------------------------------------------------------------------------------------------------------
說完了打包流程,接下來說下怎麼更新,隻有能順利更新下面後,才能夠算作熱更的最後一環。關于更新這一塊,我們是用C#寫成的,為啥?因為我們真實項目中,遊戲的基礎功能,比如下載下傳、線程操作都建議在C#中完成,為了效率,而不是為了花架子都在lua中完成。因為這些基礎功能,相對于遊戲來說,更新的頻率非常之低,用C#完成追求了效率,也沒有任何損失。
我們打開Scripts/Manager/GameManager.cs檔案,定位到IEnumerator OnUpdateResource()函數,
(1)它一上來就做些初始化的操作,找到更新的位址URL等。
(2)請求更新清單檔案files.txt,因為裡面存放了上面生成的目錄結構及其MD5/CRC的資訊。
(3)分析Web伺服器上的files.txt檔案内容,然後周遊檢查本地的檔案結構是否完整、MD5是否比對。
(4)如果MD5不比對,或者本地檔案不存在,就開始建立一個下載下傳請求,并且将它傳遞給線程,請求線程下載下傳。
(5)本地協程會每一幀查詢線程下載下傳完後是否将下載下傳的檔案名存放到下載下傳檔案清單中,如果找到,繼續下載下傳下一個,直至全部下載下傳完成。
其實當全部更新完成後,此時手機存儲的檔案結構及其内容已經是最新的了,用戶端程式便可以順利啟動,完成了熱更的最後一環。
2015/8/10 23:20:36
--------------------------------------------------------------------------------------------------------------
今天繼續更新啊,說些啥呢,說下現在的Lua端的代碼結構與怎麼建立一個新的對話框出來,因為問的人較多,稍微介紹下這塊。
經過改造過的代碼架構有了變化,原來的lua除了管理器類,比如GameManager、NetworkManager等,每個面闆檔案直接就是一個類似xxxPanel.lua的格式,有人喜歡這個形式,有的人讨厭,覺得不夠專業化,強調用過多。口味難調。
後來将xxxPanel.lua分開了,一個是純粹的View層,名稱還是xxxPanel.lua形式,它裡面維護了面闆的GameObject上面所有的控件變量,以便提供給xxxCtrl.lua使用,你可以用工具代碼生成這一層。相比之下,大量的操作邏輯移到了xxxCtrl.lua裡面,這樣View層跟Controller層就此分離開了。那Module層因為沒有資料,是以還是使用者自己添加吧,我就不畫蛇添足,免得被人罵。
我們繼續說Controller層,既然有了這一層,那就得有個管理器去管理Controller層,是以就出現了CtrlManager.lua,它裡面維護了所有的控制器的關系,我們可以通過它擷取需要的Controller,進而Open、Close操控View層。這樣解釋完,基本上都懂得為啥要這樣操作了吧~~
接下來我們說下,怎麼建立一個新的面闆,樣例代碼請參考最新的版本,當下是0.3.7 f4版本。
(1)建立一個Unity3d的面闆對象,不管你使用UGUI還是NGUI,請做好布局準備。
(2)如果是NGUI,請将這個面闆的圖集、Prefab等檔案,加入到Editor/Package.cs的打包函數裡面。
(3)如果是UGUI,請給這個面闆的Prefab一個AssetBundle名稱(我們用的U5新版打包方式),
(4)面闆的名稱請以"xxxPanel"命名,然後單擊Game菜單Build XXX Resource打包素材。
(5)在lua中的Controller目錄中添加相應控制器,比如MessageCtrl.lua,裡面的格式按照架構示例添加。
(6)在lua中的View目錄中添加相應的視圖層,比如MessagePanel.lua,裡面添加好面闆的Button、Image的變量關聯。
(7)在Logic/GameManager.lua裡面的LuaScriptPanel函數裡面添加面闆的名稱,作用是lua告訴c#哪些面闆的lua檔案需要提前加載到luavm。
(8)在CtrlManager.lua裡面按照相應的格式,添加初始化控制器代碼。
(9)非常非常重要的一步!!(很多人都會忽略),記得在Common/define.lua的初始化面闆table中添加"MessagePanel",這樣當C#的GameManager初始化的時候,才會将這個MessagePanel.lua注冊進lua虛拟機裡面。再當顯示面闆的時候,才不會出現類似"Push xxxPanel failed"的操作提示。
啟動吧~
--------------------------------------------------------------------------------------------------------------
今天幫大家梳理下新版架構的頭,可能會說不完,慢慢更新吧。
看過老版架構同學應該知道,我的架構有個全局構造器“GlobalGenerator”對象,是架構的第一入口,之前的遊戲管理器“GameManager”起源于它,InitGameMangager,也就是在它身上腳本用Prefab執行個體化的,但是新版裡面沒有了GameManager的Prefab,變成了直接new GameObject(),為了精簡。
GameManager的對象建立了,需要往它身上添加管理器,這個跟原來的方式相同,沒啥變化。但是變得有些繞,我也不能說PureMVC不好,但是的确不是我喜歡的,沒辦法,用的人多就是真理,順了它了。
有一行代碼AppFacade.Instance.StartUp(); //啟動遊戲,它其實就是啟動PMVC,不懂的,自己查文檔去,别問我。這行會啟動PMVC架構,進到函數裡面,可以看到,它裡面就2行代碼,一個是發送Command,一個是移除Command,一次性的用完就删,全民好習慣,不用誇我。
那這個指令是在什麼地方注冊的?上面
override protected void InitializeController()
{
base.InitializeController();
RegisterCommand(NotiConst.START_UP, typeof(StartUpCommand));
}
是以有了注冊,下面有了發送,那我們開始找接收的地方,在Controller/Command/StartUpCommand.cs裡面了,
裡面除了檢查架構運作環境的Util.CheckEnvironment()之外,後面還有3行啟動指令,我日,好麻煩,什麼玩意兒,我當時學到此,也是這種感覺。
//BootstrapModels
AddSubCommand(typeof(BootstrapModels));
//BootstrapCommands
AddSubCommand(typeof(BootstrapCommands));
//BootstrapViewMediators
AddSubCommand(typeof(BootstrapViewMediators));
其實就是啟動MVC各自層的子指令,PMVC作者你過來過來,我保證不打死你。
别的先不看,先打開看下中間的BootstrapCommands類吧,進去之後,我們看到:
裡面除了添加了一條新消息Facade.RegisterCommand(NotiConst.DISPATCH_MESSAGE, typeof(SocketCommand));
為了Socket消息做準備外,下面就是一段怎麼添加管理器,我日,facade啥東西?
在PMVC裡面,它的含義叫“門面”,他們不建議用單例,建議facade是以前外部通路架構内部的總入口,為了解耦。
那我就按照它的規則用了:Facade.AddManager(ManagerName.Lua, new LuaScriptMgr());
挨個的添加每個管理器,老版使用者對這一幕很熟悉,原來是用Util.Add<GameManager>(gameObject)添加的,那這個Facade.AddManager也是類似功能,隻是将原來的Util.Add轉移到了Facade中,那我們可以繼續跟進去看下AddManager怎麼操作的?
//SimpleFramework Code By Jarjin lee
void AddManager(string typeName, object obj);
T AddManager<T>(string typeName) where T : Component;
T GetManager<T>(string typeName) where T : class;
void RemoveManager(string typeName);
這是我建立的4個接口定義,原PMVC沒有這些,單擊AddManager的引用實作函數,大概在Facede.cs的523行位置,就是我4個函數體的實作部分,
GameObject AppGameManager {
get {
if (m_GameManager == null) {
m_GameManager = GameObject.Find("GameManager");
}
return m_GameManager;
}
}
原來如此,我找到新New出來的GameManager,然後根據傳進來的不同的類型T,添加到了GameManager對象身上,完成了原來很簡單的Util.Add操作,
多說兩句,為啥我腦殘非要放到這裡?原因是facade的設計是全架構通用,任意位置都可以直接通路,這個構想跟我原來的ioo類是一樣的,為了搭上它的順風車,讓架構任意地方都能通路到所有的管理器,是以,隻能在這裡找個安身之所。被這麼繞了半天,我也挺需要安慰的,畢竟不是我設計的PMVC。
如果能看到PMVC作者,我非要第一個上去,給他一腳,但是誰讓用它的多呢?