在上篇文章 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
end

PanelName则是在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;
end

3、启动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

那么有什么办法让我们刚刚改的代码生效呢?

思路有两个:

  1. 将们的写的代码打包到StreamAssets中;
  2. 让程序直接运行打包前的代码;

思路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);
end

4、添加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创建自己的面板的更多相关文章

  1. Unity3D热更新之LuaFramework篇[03]--prefab加载和Button事件

    在上一篇文章 Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板 中,我介绍了LuaFramework加载面板的方法,但这个方法并不适用于其它Prefab资源,在这套框 ...

  2. Unity3D热更新之LuaFramework篇[10]--总结篇

    背景 19年年初的时候,进到一家新单位,公司正准备将现有的游戏做成支持热更的版本.于是寻找热更方案的任务就落在了我头上. 经过搜索了解,能做Unity热更的方案是有好几种,但是要么不够成熟,要么不支持 ...

  3. Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法

    时隔一个多月我又回来啦! 坚持真的是很难的一件事,其它事情稍忙,就很容易说服自己把写博客的计划给推迟了. 好在终于克服了自己的惰性,今天又开始了. 本篇继续我的Luaframework学习之路. 一. ...

  4. Unity3D热更新之LuaFramework篇[07]--怎么让unity对象绑定Lua脚本

    前言 在上一篇文章 Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的 中,我分析了由LuaBehaviour来实现lua脚本生命周期的方法. 但在实际使用中 ...

  5. Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现

    前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...

  6. Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween

    在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此 ...

  7. Unity3D热更新之LuaFramework篇[01]--从零开始

    前言 因工作关系,需要对手头的项目进行热更新支持.了解后发现,Lua的几个变种:XLua.ToLua(原uLua)和Slua都可以做Unity热更,而ToLua更是提供了一个简易的热更框架--LuaF ...

  8. Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建

    前言 前面铺垫了这么久,终于要开始写热更新了. Unity游戏热更新包含两个方面,一个是资源的更新,一个是脚本的更新. 资源更新是Unity本来就支持的,在各大平台也都能用.而脚本的热更新在iOS平台 ...

  9. Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的

    前言 用c#开发的时候,新建的脚本都默认继承自Monobehaviour, 因此脚本才有了自己的生命周期函数,如Awake,Start, Update, OnDestroy等. 在相应的方法中实现游戏 ...

随机推荐

  1. Python从入门到精通之Third!

    Python运算符 算数运算符:+    -    *   /     %    //    **  比较运算符:==    >     <     >=   大于等于      & ...

  2. 使用EasyUI的Datagrid的Editor进行行编辑,Enter回车结束编辑,并开启新的一行。

    //新增数据function add() { if (Index == undefined) { row = { move_date: '', start_time: '', end_time: '' ...

  3. 解决在静态页面上使用动态参数,造成spider多次和重复抓取的问题

    我们在使用百度统计中的SEO建议检查网站时,总是发现“静态页参数”一项被扣了18分,扣分原因是“在静态页面上使用动态参数,会造成spider多次和重复抓取”.一般来说静态页面上使用少量的动态参数的话并 ...

  4. (PMP)第2章-----项目运行环境

    1.事业环境因素:(客观存在,可能有帮助或阻碍,项目经理必须遵守) 内部:文化,结构,治理:设施和资源的地理分布,基础设施,信息技术软件,资源可用性,员工能力 外部:市场条件,社会和文化,法律限制,商 ...

  5. Unity3D编辑器扩展(一)——定义自己的菜单按钮

    Unity3D 引擎的编辑器拥有很强的扩展性,用的好可以帮我们省很多事情.在这里记录下如何去扩展 Unity3D 的编辑器,定制属于我们自己的开发环境. 本篇主要讲解在 Unity3D 引擎的各个窗口 ...

  6. 20个Linux防火墙应用技巧

    转载 1.显示防火墙的状态 以root权限运行下面的命令: # iptables -L -n -v 参数说明: -L:列出规则. -v:显示详细信息.此选项会显示接口名称.规则选项和TOS掩码,以及封 ...

  7. How to setup Visual Studio without pain

    Visual Studio (VS) can be very hard to install. If you are lucky, one whole day may be enough to ins ...

  8. 20145232韩文浩《网络对抗》MSF基础应用

    MS08-067漏洞攻击 攻击机:Kali:192.168.31.132 靶机:win XP SP3(English):192.168.31.180 在VMware中设置两台虚拟机网络为NAT模式,自 ...

  9. volatile的使用

    //资源(把 volatile去掉进行测试 )public class Demo { volatile int i =1;}//测试 public static void main(String[] ...

  10. 关于http与https的注意点

    背景:在一次项目生产上线中遇到地址在IOS版本的app中打不开或者接口请求不返回的情况,在安卓机和PC上表现正常,经排查,问题出在http请求上,原因详解 在早期PC上和安卓手机上比较不严格,在htt ...