[Unity熱更新]tolua# & LuaFramework(一):基礎


一、tolua#

c#調用lua:LuaState[變量名/函數名]

1.LuaState
a.執行lua代碼段
DoString(string)
DoFile(.lua文件名)
Require(.lua文件名(但沒有.lua后綴))

b.獲取lua函數或者表
LuaFunction func = lua.GetFunction(函數名);             或者           LuaFunction func = lua[函數名] as LuaFunction;
LuaTable table = lua.GetTable(表名);

c.Start():如果需要使用wrap,則需要調用該方法


2.LuaFunction
Call()


3.LuaTable

LuaTable[變量名/函數名]

ToArray()


lua調用c#

在c#中將引用傳遞到lua中后:

1.通過“.” (點號)來使用非靜態的變量以及靜態的變量與方法

2.通過'':“ (冒號)來使用非靜態的方法

3.通過"{}"來傳遞數組給c#

4.創建GameObject:newObject(變量)

5.摧毀GameObject:destroy(變量) 

6.獲取組件:GetComponent('LuaBehaviour')


二、LuaFramework(使用PureMVC)

a.基礎模塊

1.Util:對Mono的功能進行封裝,這樣不繼承Mono的類就能使用Mono的東西了(如transform.Find、GetComponent);還有其他的工具方法

2.AppFacade:繼承Facade,整套框架的入口

3.Base:繼承MonoBehaviour,是一切View和Manager的基類;持有各種Manager的引用;能注冊移除(view所感興趣的)信息

4.View:只有一個方法:public virtual void OnMessage(IMessage message) 這是處理信息的方法

5.Manager:繼承Base

6.AppView:繼承View,是一個范例:注冊View所感興趣的信息,處理信息


b.lua模塊

1.LuaFileUtils:通過.lua文件路徑和AssetBundle文件路徑這兩種方式來找.lua文件,並讀取返回byte[]

2.LuaLoader:繼承LuaFileUtils,並無重要變化

3.LuaEvent:類似c#中的event,提供Add和Remove方法

4.LuaLooper:繼承MonoBehaviour,在Update / LateUpdate / FixedUpdate中執行對應的LuaEvent

5.LuaBinder:如果執行的.lua文件需要用到unity中的類型,則需要用這個類給LuaState進行綁定

6.LuaManager:繼承Manager,入口類,初始化Lua代碼加載路徑(調試模式下是在Assets \ LuaFramework目錄下,非調試模式是在C:\luaframework\lua(window系統),默認是非調試模式),引用一個LuaState並封裝其功能(讀取lua文件、調用方法等)

7.LuaBehaviour:繼承View,在Awake / Start中調用lua中對應的方法;並提供點擊事件的相關處理


c.Manager模塊

1.ResourceManager:加載AssetBundle的相關操作。在pc平台上默認加載的是Assets\StreamingAssets里的東西,移動平台上則是Application.persistentDataPath。那么如果我們想在pc平台上像移動平台一樣讀取外部路徑(使用www),在pc平台模擬熱更新,那么就可以在Initialize這個方法修改:m_BaseDownloadingURL = "file:///" + Util.DataPath;


unity5加載AB包的四個步驟:

a.為assetbundle起名字,並打包

b.加載總的清單文件

c.加載assetbundle的依賴文件

d.加載assetbundle


m_Dependencies:key為AB包的名字,value為依賴的AB包的名字

m_LoadedAssetBundles:key為AB包的名字,value為加載后的AB包

m_LoadRequests:key為AB包的名字,value為對包內資源的請求


先通過Initialize方法加載總的清單文件,然后我們可以通過LoadPrefab方法來加載AB包,此時會把對這個AB包的請求放在m_LoadRequests中,然后在OnLoadAsset方法對該AB包的所有請求進行處理,通過GetLoadedAssetBundle方法看看內存中有沒有這個AB包,如果有的話,再檢查一下該AB包的依賴包是否也在內存中,如果都在,就把請求的包內資源加載出來,並回調方法。如果出現缺包情況,會通過OnLoadAssetBundle方法加載AB包及其依賴包(使用遞歸)。

至於卸載AB包,使用的是UnloadAssetBundle方法。這里還有說一下引用計數的問題,例如有A1A2A3三個包,A2A3依賴A1,然后我們加載A2A3。那么A1的引用計數為2,A2的引用計數為1,A3的引用計數為1,當使用UnloadAssetBundle卸載掉A2包時,A1的引用計數變為1,此時還會留在內存中,再卸載A3包,A1的引用計數變為0,A1包就自動被卸載了。包被加載一次,則引用計數加1,所以上面的A2A3包引用計數為1,;包被依賴一次,則引用計數加1,所以上面的A1包引用計數為2,;每次卸載時計數減1,減到0則從內存中去掉。


2.PanelManager:默認lua創建的panel都要在tag為GuiCamera的物體下,提供創建panel的方法

3.ThreadManager:解包與下載資源


lua代碼分析:

PromptPanel.lua

1.函數是可以存儲在變量中的。函數與其他所有值都是匿名的,即它們都沒有名稱。當討論一個函數名時,實際上是在討論一個持有某函數的變量。

[csharp]  view plain  copy
  在CODE上查看代碼片 派生到我的代碼片
  1. a = {p = print}    
  2. a.p("hello woeld")     --hello woeld    
  3. print = math.sin    
  4. a.p(print(3.14159))    --約等於0    
  5. sin = a.p    
  6. sin(10,20)             --10 20    
所以對於:function foo(x) return 2*x end                                             其實就是等於:foo = function (x) return 2*x end
那么對於:function PromptPanel.Awake(obj)  xxx end                     其實就是等於:PromptPanel.Awake = function (obj)  xxx end


2.引用table

[csharp]  view plain  copy
  在CODE上查看代碼片 派生到我的代碼片
  1. a = {}                --創建一個table,並將它的引用存儲到a    
  2. a["x"] = 10    
  3. b = a                 --b與a引用了同一個table    
  4.     
  5. print(b["x"])         --10    
  6. b["x"] = 20    
  7. print(a["x"])         --20    
  8. a = nil               --現在只有b還在引用table    
  9. b = nil               --再也沒有對table的引用了    



3.

[csharp]  view plain  copy
  在CODE上查看代碼片 派生到我的代碼片
  1. a = {}    
  2. x = "y"    
  3. a[x] = 10    
  4. print(a[x])    --10    
  5. print(a.x)     --nil    
  6. print(a.y)     --10    
  7.     
  8. --a.x等同於a["x"]   
那么,對於上面的PromptPanel.Awake,就是等於PromptPanel["Awake"]


PromptCtrl.lua

1.對於沒有local聲明的變量均為全局變量,可以在其他.lua文件中調用

2.在Common/define.lua中注冊View、Controller,define.lua中持有各種manager的引用


PromptPanel & PromptCtrl:PromptPanel維護了面板的控件變量,提供給PromptCtrl使用,沒有model層是因為沒有數據

CtrlManager:管理controller層,維護所有的controller

Game:在OnInitOK方法中指定開始的panel,例如例子中的:local ctrl = CtrlManager.GetCtrl(CtrlNames.Prompt);


總結

1.對於一個panel,需要添加或修改的文件:

a.添加xxxPanel & xxxCtrl

b.修改define、Game、CtrlManager

詳細的可見:http://blog.csdn.net/adambieber/article/details/47402805


2.在lua中使用AB包內的資源的兩種方法:

a.panelMgr:CreatePanel('Prompt', this.OnCreate);

b.resMgr:LoadPrefab('prompt', { 'PromptItem' }, this.InitPanel);

其中a是對b的進一步封裝,因此兩者都需要提供AB包名、要訪問的包內資源名字(如果是panel,則默認資源名為AB包名+"Panel")以及回調方法(參數是AB包中的資源)


3.熱更新的四個步驟:打包、解包、更新和加載。而這四個步驟框架已經給我們封裝好了,基本上就不需要我們去管了,但還是很有必要理解其中的過程。

a.打包:將資源全部打包到StreamingAssets文件夾

打包類:LuaFramework / Editor / Packager 

打包lua文件:HandleLuaBundle,對Assets\LuaFramework\Lua 與 Assets\LuaFramework\ToLua\Lua這兩個目錄下的所有lua文件進行打包

打包圖片等資源:HandleExampleBundle


b.解包:在移動端StreamingAssets這個文件夾是只讀的,但是要做熱跟新的話,就需要寫入文件,因此Application.persistentDataPath這個可讀可寫的路徑才是數據在移動端的存放路徑,同時也為了比較MD5的值,就需要將StreamingAssets的東西解包(復制)到Application.persistentDataPath


c.更新:files.txt這個文件記錄了所有的資源文件及其MD5值,每次進入游戲時都會從服務器下載最新的files.txt,然后對其遍歷比較MD5值,如果值不同或者不存在則下載


d.加載:先加載資源的依賴,再加載資源


那么,如果我們對外發布了一個版本1.1,然后更改資源,發布1.2,要做的就是:重新生成apk並上傳,然后將StreamingAssets文件夾下的東西上傳到服務器,具體位置見AppConst.WebUrl;對於用戶來說,如果他安裝的是1.1,那么就會下載更新,如果他安裝的是1.2,那么解包之后就得到最新的資源了,無需更新了。



4.整套框架的工作流程:

c#                                                                                                                                                         

打包好后,啟動游戲,GameManager會進行一些判斷,如果這是游戲安裝之后的第一次啟動,那么就會進行解包操作。如果AppConst.UpdateMode為false,那么就不會檢測更新,否則就會進行更新操作。然后進入初始化操作,調用Game.lua中的OnInitOK方法,進入lua邏輯。

lua

然后調用指定控制器的Awake方法、PanelManager的CreatePanel方法,調用c#代碼,創建panel,為其添加LuaBehaviour,調用xxxPanel.lua的方法,獲取控件引用,進行邏輯處理。


From:http://blog.csdn.net/lyh916/article/details/45021703



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM