在上篇文章 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的预制体以及按钮事件处理。