1. 程式人生 > >Ulua熱更新提高 Ulua_SimpleFramework框架流程詳解

Ulua熱更新提高 Ulua_SimpleFramework框架流程詳解

原創

以前寫過幾篇關於熱更新的文章,但是我一直沒有深入研究,就是公司用什麼技術,我就根據公司的框架寫程式碼。這回剛好在家閒著,我打算寫一個系列的文章,深入研究一下Uua的熱更新。最近幾天有2家公司挖我去做遊戲,開門問我第一句都是熱更新框架你能不能搭建起來,COCOS做2D有LUA是不是比U3D強,搞的我腰板也是不太硬,都是因為熱更新懂的不是很徹底,工資都沒有到20K,雖然自信自己的學習能力,很快就能研究完,但是還是要從頭搞一遍才行。

目前主流的ULua有兩套框架,一個是SimpleFramework_UGUI ,16年初以後不維護了。一個是LuaFramework_UGUI。本來是當算學一下LuaFramework_UGUI畢竟是原作者的新東西。但是看一下,竟然打包資源還要手動加程式碼,再加上商用估計都還是老的比較多,我決定還是學習SimpleFramework_UGUI ,官方教程:http://doc.ulua.org/default.asp?cateID=4

 因為接下來的專案需要短時間出東西,當然是用最成熟最方便的,以後可能會用LuaFramework_UGUI,如果需要學LuaFramework_UGUI,可以看這系列部落格:https://www.zhihu.com/people/pyluo/posts

首先:需要了解這些知識點,編輯器擴充套件,Lua指令碼語言,Unity5的AsstBundle打包,Lua和C#通訊原理。我打算先上手直接做一遍流程再深入研究。我個人不喜歡一上來就是原理,這個那個的,咱們學東西就是要快速上手能用,用順手了再去深挖!

我這裡都是以熱更新UI介面或者2D遊戲為例子。我理解的ULUA熱更新是這樣的順序:先匯入SimpleFramework_UGUI框架到專案,登入介面一個Assetbundle包,大廳一個包,使用者資訊一個包,排行榜一個包,型別這種模組化的包,需要更新那個地方就更新哪一塊,StreamingAssets資料夾下有個files檔案是包的版本資訊。我們打包了一個APK出去以後,如果有更新的模組,就放到伺服器上,通過伺服器下載遠端的files和本地的files做比對,哪些資源包不一樣,就會自動下載下來,覆蓋原有的包,第一次開啟遊戲都是需要解包的,就是把StreamingAssets包的資源拷貝到你真機的持久化儲存的地方,第二次就不需要了,直接讀取。

我的U3D版本是Unity 5.3.1,SimpleFramework_UGUI版本是16年1月份的,Lua開發工具sublime。

首先,需要注意的是:

1.如果在Lua裡建立的介面沒有指定父物體,將會建立到Tag為GuiCamera的物體下。具體看PanelManager.cs這個類。

2.如果你修改了CS類,你要Lua選單---Gen Lua Wrap Files,生成的檔案在uLua/Source/LuaWrap資料夾,Lua選單----Clean Wrap...可以清空這個資料夾。(生成的檔案可以讓Lua指令碼去呼叫C#類)

3.修改和建立了LUA指令碼就要Build Resource  (如果把AppConst類中的 DebugMode = true; 設定為除錯模式,就不會讀取本地儲存的Lua,而且是讀取工程中的Lua。也就是可以一邊修改一邊看到修改後的內容,而不用Build,但是Prefab資源修改了就一定要Build)

製作Lua資源:就是修改3個Lua指令碼(define,GameManager,CtrlManager,)和新增2個Lua指令碼(Ctrl和Panle)和資源製作(比如名字叫LoginPanel,資源包叫Login.assetBundle)

第一步,打包成AssetBundle

1.比如你做好了一個登入介面,先把該Panel介面做成prefab,注意prefab命名為  xxxxxPanel (原因是PanelManager.cs 這個類裡OnCreatePanel函式要求這麼寫,當然Scripts/Manager還有其他的管理器,有其他資源的載入方式。)

2.在右下角把該Panel的AssetBundle 命名為  xxxxx (不要Panle),字尾為 AssetBundle

3.Game選單----build  Windows Resource     會在StreamingAssets資料夾下生成的lua程式碼和資源包,正式專案打包最好先刪除這個資料夾再Build

注意:如果你有Json,或者其他文字形式的檔案想打包,直接放在StreamingAssets下,會打包進檔案目錄files.txt

第二步,用lua建立UI面板

1.新建一個物體叫GlobalGenerator,給他一個GlobalGenerator指令碼,這個是Lua入口,再往下看GameManager類的OnResourceInited()方法,他會去呼叫GameManager.lua腳本里的LuaScriptPanel函式(CallMethod("LuaScriptPanel")  ),如果返回 xxxxx,就回去執行 Lua/view/xxxxxPanel指令碼。

2.接著會執行GameManager.Lua裡的GameManager.OnInitOK()方法,會執行CtrlManager.Init(); 在CtrlManager.Lua指令碼   require "Controller/xxxxxCtrl"然後再Init函式中加上  ctrlList[CtrlName.xxxxx] = xxxxxCtrl.New(); 

3.在Define.Lua指令碼中的CtrlName表中加入  xxxxx="xxxxxCtrl"

4.新增一個UI模組,需要新增上面說到的有兩個Lua指令碼,一個是Lua \ View \ xxxxxPanel  ,一個是Lua \ Controller \ xxxxxCtrl。 這兩個指令碼等會再說,可以先仿照官方的例子來寫。

5.GameManager.Lua指令碼在CtrlManager.Init();執行完後,會通過得到的Ctr指令碼,執行ctrl:Awake();  就是一句建立面板  PanelManager:CreatePanel('xxxxx', this.OnCreate);  前面一個引數是AssetBundle的包名(其實也是Prefab的名字,會自動加一個"Panel",在PanelManager.cs的CreatePanel函式中可以去看),後面一個引數是回撥。  例子是是回撥到LogCtrl.OnCreate(obj)這個函式,Obj是什麼東西呢,其實就是建立的物體(在PanelManager.cs類裡的CreatePanel函式,func.Call(go);)  建立的這個物體會先載入本地持久化目錄的資源,然後建立一個UI物體,並給它掛載一個LuaBehaviour元件。LuaBehaviour裡面就可以讓xxxxxPanel.Lua指令碼執行U3D裡的Awake,Start函式,以及AddClick新增點選事件等。

6. 編寫Ctrl和Panel的Lua檔案

正式專案中,應該寫一個LayerPanel,下面有前中後三層,就可以給生產的Panel指定父物體來,來改變顯示的前後順序。

Panel檔案只負責UI介面的引用。

his.Btn_Ok = transform:FindChild("Btn_Ok").gameObject;

Ctrl檔案的程式碼應該這麼寫(負責點選事件,建立關閉面板等):

LoginCtrl = {};
local this = LoginCtrl;

local Login;
local transform;
local gameObject;

--構建函式--
function LoginCtrl.New()
	return this;
end

function LoginCtrl.Awake()
	PanelManager:CreatePanel('Login', this.OnCreate);
end

--啟動事件--
function LoginCtrl.OnCreate(obj)
	gameObject = obj;
	transform = obj.transform;

    Login = transform:GetComponent('LuaBehaviour');
	Login:AddClick(LoginPanel.gameObject, this.OnClick);  --新增點選事件
end

--單擊事件--
function LoginCtrl.OnClick(go) 
    logError("你點選了!"); this.Close();
end

Panel裡負責面板的引用

--啟動事件--
function GameFruitPanel.Awake(obj)
	gameObject = obj;
	transform = obj.transform;

    transform:SetParent(LayerPanel.Layer_B);  --設定父物體

	local  Rect = gameObject:GetComponent("RectTransform"); --設定位置,大小
	Rect.localPosition=Vector3.zero;        --Vector3是框架給我寫好的,在Lua / System裡,其實就是一個表。
    Rect.sizeDelta=Vector3.one;

	this.InitPanel();

end


另外,呼叫Update()  

新增UpdateBeat:Add(PromptCtrl.Update)      移除UpdateBeat:Remove(PromptCtrl.Update)  具體還沒研究,只知道這麼用,用完要移除掉,很耗效能。

為什麼要分開寫,為什麼要一個UI介面寫2個Lua, 是因為Ulua的框架結構是PureMVC基於模型、檢視和控制器的三層MVC模式,這裡xxxxxPanel.lua是介面展示和引用UI元素,也就是檢視層,xxxxxCtrl.lua就是業務邏輯層,像define.lua就是資料層。當然你可以每個面板搞一個數據層存一下,我感覺沒什麼必要,只存全域性資料就行了。

7.新增自定義元件。

開啟 Ulua  /  Editor / WrapFile.cs檔案, 新增: _GT(  typeof(類名)  ) , 然後開啟選單Lua---Gen  lua Wrap Files,生成該C#類對應的Warp檔案,有了這個檔案才能給Lua指令碼使用,生成的Wrap檔案在uLua  / Source/  LuaWrap裡。

8.生成EXE或者APK。需要注意一下幾點:

1.生成哪個平臺,Game選單下選擇哪個平臺的資源

2.選擇生成的平臺,PC要選擇PC--- Architecture:  X86_64 ,如果選擇X86會找不到Ulua.DLL

3.生成選項:Development build ,會在遊戲中列印日誌資訊,並且儲存在一個 log.txt裡。

   生成選項:Autoconnect profiler,自動連線分析器,開啟U3D效能分析工具的功能。(點Build And Run)

   生成選項:Script debugging,開啟指令碼除錯

在生成匯出的時候,還報錯: The nested type `AdvertisingIdentifierCallback' does not exist in the type `UnityEngine.Application'

這個問題我搞了好久,問了蠻多人,最後的解決方法:直接用U3D開啟SimpleFramework_UGUI解壓的工程,就不會報錯,如果是Uua匯入你原先的專案就會報錯,有可能是我匯入的時候少放了東西。

如果,報錯:Push table failed  就是GameManager.LuaScriptPanel忘了添加了。

如果,編輯器沒問題,但是到真機上報錯:Loader lua filed System.Global,在AppConst設定除錯模式DebugMode=false

--關閉事件--
function LoginCtrl.Close()
	PanelManager:ClosePanel(CtrlName.Login);
end

Ctrl檔案裡的,我發現PanelManager.cs裡沒有ClosePanel這個方法,需要我們自己寫

        /// <summary>
        /// 關閉面板
        /// </summary>
        /// <param name="name"></param>
        public void ClosePanel(string name){
            var panelName = name + "Panel";
         // var panelObj = Parent.FindChild  (panelName);  
            var panelObj =  GameObject.Find(panelName);
            if (panelObj == null) return;
            Destroy(panelObj.gameObject);
        }