Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板
在上篇文章 Unity3D热更新之LuaFramework篇[01]--从零开始 中,我们了解了怎么获得一个可用的LuaFramework框架。
本篇将我会先介绍一下如何配置Lua开发环境,然后分析在此框架中加载面板的流程,以及如何创建自己的面板。
1、配置Lua开发环境
有一点要说明的是,使用此种方式(ToLua+LuaFramework)做热更新,则意味着你的大部分逻辑都需要改用Lua语言来编写。
因此,开发前得先得配置好Lua开发环境。毕竟,工欲善其事,必先利其器。
环境配置大概分以下三个步骤:
1.安装IntelliJ IDEA Community Edition 2018.2.4 x64
官网地址 http://www.jetbrains.com/idea/download/#section=windows
直接下载即可,下载 Community 版本,也就是社区版,免费的
2.下载Lua For Windows
https://github.com/rjpcomputing/luaforwindows/releases
下载最新的就行,然后安装。
3.安装emmylua插件
安装插件有2种方法,可以直接搜插件库安装,或者下载好插件后本地加载。
以上安装步骤均来自:三页菌 的文章 最好用的lua编辑器--------emmylua使用汇总。
其文章极其详细的介绍了如何搭建并配置一个好用的Lua开发环境,请自行参考。
2、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个重要逻辑:
1、初始化View
2、初始化Ctrl
3、启动Ctrl
1、初始化View
初始化View就是调用InitViewPanels这个函数,InitViewPanels函数用于加载View目录下定义的XxxPanel,在Game.lua的17行中可以看到定义。
function Game.InitViewPanels()
for i = , #PanelNames do
require ("View/"..tostring(PanelNames[i]))
end
endPanelName则是在LuaFramwwork/Lua/Common/define.lua的第7行中定义的,对应面板的名称。
PanelNames = {
"PromptPanel",
"MessagePanel",
}2、初始化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;
end3、启动Ctrl
启动就是根据CtrlNames找到对应的Ctrl的实例,然后调用其Awake方法,见代码:
local ctrl = CtrlManager.GetCtrl(CtrlNames.Prompt);
if ctrl ~= nil and AppConst.ExampleMode == 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。
3、如何创建自己的面板
在上一步的分析中,我们得知创建一个面板需要先初始化View,再实例化Ctrl,然后调用Ctrl的Awake。这些都是代码层面的,前提还有一个,我们需要一个XxxPanel预制体。
总结一下,如果要创建一个我们自己的面板,则需要如下步骤:
1、创建一个XxxPanel预制体
2、创建对应的XxxPanel脚本
3、创建对应的XxxCtrl脚本
4、添加CtrlNames及PanelNames
5、加载XxxCtrl
下面我将以FirstPanel为例进行演示。
1、创建FirstPanel预制体。
在Hierarchy面板中创建一个FirstPanel,并在LuaFramework目录下新建CustomPrj/FirstTest目录,将FirstPanel拖到此做成预制体,见图3-1。
图3-1
然后删掉Hierarchy面板中的FirstPanel,因为后面我们会动态加载它。
2、创建FirstPanel.lua脚本。
在Lua/View目录下创建一个FirstPanel的lua脚本,脚本结构参照MessageView编写,如下:
local 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。
3、创建FirstCtrl.lua脚本。
在Lua/Controller目录下创建一个FirsCtrl的lua脚本,脚本结构参照MessagCtrl编写,如下:
FirstCtrl = {};
local this = FirstCtrl; local message;
local transform;
local gameObject; --构建函数--
function FirstCtrl.New()
logWarn("FirstCtrl.New--->>");
return this;
end function FirstCtrl.Awake()
logWarn("FirstCtrl.Awake--->>");
panelMgr:CreatePanel('First', this.OnCreate);
end --启动事件--
function FirstCtrl.OnCreate(obj)
gameObject = obj; message = gameObject:GetComponent('LuaBehaviour'); --这句要注释掉,因为我们的FirstPanel中没有按钮
--message:AddClick(MessagePanel.btnClose, this.OnClick); logWarn("Start lua--->>"..gameObject.name);
end --单击事件--
function FirstCtrl.OnClick(go)
destroy(gameObject);
end --关闭事件--
function FirstCtrl.Close()
panelMgr:ClosePanel(CtrlNames.Message);
end4、添加CtrlNames及PanelNames
在Lua/Common找到define.lua,在CtrlNames中添加 First = "FirstCtrl",在PanelNames中添加"FirstPanel",如下:
CtrlNames = {
Prompt = "PromptCtrl",
Message = "MessageCtrl",
First = "FirstCtrl"
} PanelNames = {
"PromptPanel",
"MessagePanel",
"FirstPanel"
}5、加载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 == 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预制体进行打包操作。
操作如下:
1、找到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");
}2、执行unity编辑器上方LuaFramework菜单中的Build Windows Resources菜单项,进行打包操作。打包完成后,可以在StreamingAssets目录中看到first.unity3d文件。见图3-6
图3-6
再次运行,
这次终于得到了我们想要的结果,我们自己创建的面板FirstPanel,就这么加载出来了。
见图3-7
图3-7
真是太不容易了!
现在,将我们改错的经过都加入到完整的步骤中,那么,加载一个我们自己创建的面板的完整步骤如下:
1、创建一个XxxPanel预制体
2、创建对应的XxxPanel脚本
3、创建对应的XxxCtrl脚本
4、添加CtrlNames及PanelNames
5、在CtrlManager中加入对XxxCtrl.New的调用,并在头部require "XxxCtrl"
6、在Packager.cs文件中对XxxPanel预制体进行打包
7、在Game.lua加载XxxCtrl
后续写模块的时候都会按这个流程来。
后记
在本篇文章的第二节的写作过程中,为什么我会用推测并验证的写法,而不是直接给出一个正确结论?第三节中,我为什么没有直接给出正确的操作步骤,而是边走边改错?
因为我希望本文能如实还原我学LuaFramework的过程,记录每一个问题的发生条件,以及我解决问题的思路。
下一篇文章将会介绍如何加载非XXXPanel的预制体以及按钮事件处理。
Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板的更多相关文章
- Unity3D热更新之LuaFramework篇[03]--prefab加载和Button事件
在上一篇文章 Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板 中,我介绍了LuaFramework加载面板的方法,但这个方法并不适用于其它Prefab资源,在这套框 ...
- Unity3D热更新之LuaFramework篇[10]--总结篇
背景 19年年初的时候,进到一家新单位,公司正准备将现有的游戏做成支持热更的版本.于是寻找热更方案的任务就落在了我头上. 经过搜索了解,能做Unity热更的方案是有好几种,但是要么不够成熟,要么不支持 ...
- Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法
时隔一个多月我又回来啦! 坚持真的是很难的一件事,其它事情稍忙,就很容易说服自己把写博客的计划给推迟了. 好在终于克服了自己的惰性,今天又开始了. 本篇继续我的Luaframework学习之路. 一. ...
- Unity3D热更新之LuaFramework篇[07]--怎么让unity对象绑定Lua脚本
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的 中,我分析了由LuaBehaviour来实现lua脚本生命周期的方法. 但在实际使用中 ...
- Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...
- Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween
在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此 ...
- Unity3D热更新之LuaFramework篇[01]--从零开始
前言 因工作关系,需要对手头的项目进行热更新支持.了解后发现,Lua的几个变种:XLua.ToLua(原uLua)和Slua都可以做Unity热更,而ToLua更是提供了一个简易的热更框架--LuaF ...
- Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建
前言 前面铺垫了这么久,终于要开始写热更新了. Unity游戏热更新包含两个方面,一个是资源的更新,一个是脚本的更新. 资源更新是Unity本来就支持的,在各大平台也都能用.而脚本的热更新在iOS平台 ...
- Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的
前言 用c#开发的时候,新建的脚本都默认继承自Monobehaviour, 因此脚本才有了自己的生命周期函数,如Awake,Start, Update, OnDestroy等. 在相应的方法中实现游戏 ...
随机推荐
- 作业 -- 几道简单的Python题
1.编写程序,要求生成10240个随机[0,512)之间的整数,并统计每个元素出现的次数. 2.编写程序,要求当用户输入一个列表和两个整数作为下标时,程序可以使用切片获取并输出列表中截取两个下标之间的 ...
- oracle odbc mysql 字段不全
主要是字段集不对,mysql的字符集默认设置为utf8,odbc才是unicode编码连接,无法转发.选择ansi连接方式即可.
- 1030 Travel Plan Dijkstra+dfs
和1018思路如出一辙,先求最短路径,再dfs遍历 #include <iostream> #include <cstdio> #include <vector> ...
- eclipse 无法记住svn密码
每次要求输入密码,很恼人.经过一番折腾,在stackoverflow上找到了解决方案,上面大神果然多 简单的说,就是通过查看工作空间的日志文件,发现报了个java异常,缺少一个class文件(org. ...
- MapGIS数据中心设计器 帮助文档
我以为是数据设计呢..数据设计按钮在哪里??? 数据库设计和管理(没mapgis k9那么好找)(可以编辑sql数据,可以开发吗?)文件中肯定是不行的,要网络发布,肯定是要导入sql数据库中的(或者是 ...
- java面试一、1.5JVM
免责声明: 本文内容多来自网络文章,转载为个人收藏,分享知识,如有侵权,请联系博主进行删除. 1.5.JVM JVM运行时内存区域划分
- Java 异常与反射 总结
1.异常 异常,简单来说,就是一个程序执行过程中发生的不正常情况的事件.它发生在程序的运行期间,干扰了正常的指令流程.如果没有处理异常,那么出现异常之后,程序会停止运行.异常分为运行异常和非运行异常. ...
- Django积木块六——验证用户是否登录
验证用户是否登录 # 开始在用户登录的时候验证结束后login登录 # request.user.is_authenticated() {% if request.user.is_authentica ...
- Java程序CPU使用率过高
Java程序CPU使用率过高 通过top命令找到使用率过高的java进程PID 根据进程号查找线程TID:ps -mp PID -o THREAD,tid,time 将TID转换成16进制:print ...
- Mysql函数大全以及存储过程、函数、触发器、游标等等
https://www.cnblogs.com/slowlyslowly/p/8649430.html MySQL大全 存储过程: 基本语法 : create procedure sp_name([[ ...