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 = 1, #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 == 1 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、创建对应的XxxView

3、创建对应的XxxCtrl

4、添加CtrlNames及PanelNames

5、加载XxxCtrl

下面我将以FirstPanel为例进行演示。

1、创建FirstPanel预制体。

我们在Hierarchy面板中创建一个FirstPanel,并在LuaFramework目录下新建CustomPrj/FirstTest目录,将FirstPanel拖到此做成预制体,见图3-1。

图3-1

然后删掉Hierarchy面板中的FirstPanel,因为后面我们会动态加载它。

2、创建FirstView.lua脚本。

在Lua/View目录下创建一个FirstView的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编写,如下:

 1 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

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 == 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预制体进行打包操作。

操作如下:

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、创建对应的XxxView

3、创建对应的XxxCtrl

4、添加CtrlNames及PanelNames

5、在CtrlManager中加入对XxxCtrl.New的调用,并在头部require "XxxCtrl"

6、在Packager.cs文件中对XxxPanel预制体进行打包

7、在Game.lua加载XxxCtrl

后续写模块的时候都会按这个流程来。

后记

在本篇文章的第二节的写作过程中,为什么我会用推测并验证的写法,而不是直接给出一个正确结论?第三节中,我为什么没有直接给出正确的操作步骤,而是边走边改错?

因为我希望本文能如实还原我学LuaFramework的过程,记录每一个问题的发生条件,以及我解决问题的思路。

下一篇文章将会介绍如何加载Resources目录下的预制体以及按钮事件处理。

原文地址:https://www.cnblogs.com/imteach/p/10630099.html

时间: 2024-10-13 14:36:36

Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板的相关文章

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

时隔一个多月我又回来啦! 坚持真的是很难的一件事,其它事情稍忙,就很容易说服自己把写博客的计划给推迟了. 好在终于克服了自己的惰性,今天又开始了. 本篇继续我的Luaframework学习之路. 一.规范开发模式 此前的示例中,动态加载的panel都默认以GuiCamera为父节点,且面板的大小设置得有些随意,为方便后续开发,现做一些调整和规范. 1.设定本项目的开发分辨率为1334x750(Game视图分辨率也设置为这个大小): 2.调整相机,将原有的GuiCamera从Canvas下拖离出来

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

在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此事.本篇文章就来继续这个工作. 从Lua中调用C#代码 1.创建UI监听脚本 打开之前的工程,在Assets/LuaFrameworks/Scripts/Common下,创建一个UIEventEx.cs脚本,将LuaBehaviour.cs中的AddButtonClick以及AddInputFiel

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

前言 用c#开发的时候,新建的脚本都默认继承自Monobehaviour, 因此脚本才有了自己的生命周期函数,如Awake,Start, Update, OnDestroy等. 在相应的方法中实现游戏逻辑,引擎会适时调用. 而Lua在这里做为c#的一个外延语言,自然是不受Unity管理的. 不过,在前几篇文章中能看到,在XxxPanel和XxxCtrl中确实又有生命周期的影子,比如在MessagePanel.lua脚本中就存在MessagePanel.Awake和MessagePanel.OnD

Unity3D热更新全书-下载 唯一的一篇

下载在这个时代实在是太平常了,每个人都深刻的理解着下载到底是什么. 这一篇文字只是把下载的代码分享并介绍,而已. 首先,下载系统担负着几个使命. 第一.是保持客户端版本库的最新. 第二.是下载要能够比对并最少下载 第三.是要尽量快一些. 其实我们并没有写一个下载系统,因为实在没有几行代码.我们这里介绍的是一个 Http下载并保存缓存,首包从StreamingAssets读取,加载资源,三个功能在一起的模块 源码位置https://github.com/lightszero/easydown 保持

Unity3D热更新全书-脚本(一) 初识脚本

开篇之前还是要先说明,这是一份给经验并不丰富的程序员阅读的文字. 有需求.有疑惑,往下看. 第一个问题什么是脚本?程序和脚本如何区分?我们给Unity编写的组件是程序还是脚本? 这些问题本文无意去解答,因为其中混合着太多有立场的东西,站在不同的立场会有不同的看法,这其中的矛盾不是简单可以调和的. 只要提出一个观点,就很容易陷入语言大战的泥潭. 我们不妨从另一个角度来思考,为什么要分程序和脚本,是为了找一条分界线. 这条分界线叫做灵活. 我们这个专题的出发点是探讨Unity3D客户端资源更新,已这

Unity3d热更新全书-资源加载(一)从AssetBundle说起

Unity3D动态下载资源,有没有解?有,AssetBundle就是通用解,任何一本书都会花大幅篇章来介绍AssetBundle. 我们也来说说AssetBundle 我们试全面的分析一下Unity3D提供的资源加载机制 1.Resources//内嵌资源,使用方法Resources.Load,可以加载任意种类的资源,不能动态修改,卒. 2.StreamingAssets//随包资源,使用方法IO或WWW.Load.WWW.Load可以加载任意种类资源,IO仅限bytes 和 text. 3.W

Unity3d热更新全书-加载(二)如何在不用AssetBundle的前提下动态加载预设

Unity3D的主要构成大家都知道,首先是场景图,场景图上的节点构成一颗树. 每个节点对应一个GameObject对象 然后每个GameObject有若干个组件 有一些组件会与资源产生关系,比如MeshRenderer会关联材质,材质会关联shader和贴图 场景图的一部分可以被保存为一个预设,prefab. 有时候我们会需要用预设去复用,而预设的加载似乎只能通过AB去打包,其实不然,这里我们有一个开源的库就可以解决这个问题. 为什么不使用AB,可以见上一篇,加载(一),不使用AB一份资源全平台

Unity3D热更新全书-PageZero

由于深刻的认识到自己是个思维跳跃的人,深入浅出是个我还要努力很久的目标,为了让大家不至于在我乱七八糟的文字中迷失,特整理目录一份 无分类 <Unity3D热更新全书-何谓热更新,为何热更新,如何热更新> 这一篇是写给对热更新完全没概念的人 下载系列 还没写 加载系列 <Unity3d热更新全书-资源加载(一)从AssetBundle说起 > 这一篇是探讨使用AssetBundle来做资源更新的问题,希望能让更多人理解AssetBundle是有害的 脚本系列 <Unity3D热

Unity3D热更新全书-何谓热更新,为何热更新,如何热更新

首先来赞叹一下中文,何谓为何如何,写完才发现这三个词是如此的有规律. 为何赞叹中文?因为这是一篇针对新手程序员的文字,是一节语文课. 然后来做一下说文解字,也就是 何谓热更新 热更新,每个程序员一听就明白,但是它语出何处,究竟表达了什么含义,到底代表了什么,对技术有什么要求,对经验相对较少的程序员来说可能就有一层神秘面纱了. 热更新,是对hot update 或者 hot fix的翻译,计算机术语,表示在不停机的前提下对系统进行更改. hot 就是热,机器运行会发烫,hot就是不停机的意思. 热