实现:使用SimpleFramework实现热更新方式创建UI面板
注:文章使用的是UGUI的框架

1.下载框架

ulua官方地址:http://www.ulua.org/
SimpleFramework UGUI Github地址:https://github.com/jarjin/SimpleFramework_UGUI/

下载完成后为项目文件,可直接使用unity打开,目录结构如下图:

undefined

Examples/Scenes文件下放的为热更新示例项目,ulua/Examples文件夹下放的为ulua语法教程示例

2.新建场景

  1. 新建一个自己要测试的场景
  2. 创建需要热更新的面板Prefab
  3. 新建一个GameObject添加Global Generator脚本组件

层次面板目录结构:

undefined

注意:需要热更新的UI面板要以“Panel”名字结尾

3.打包文件

  1. 将TextFramePanel预制体打包进 textframe.assetbundle

  2. 单击菜单栏中 Lua/Gen Lua Wrap Files ,如果生成成功在ulua/Source/LuaWrap文件夹下看到许多包裹文件,这些文件原来是没有的。

  3. 如果修改了注册到Lua中的C#类,需要清除文件缓存,重新生成。单击Lua/Clear LuaBinder File + Wrap Files再接第二步

  4. 单击菜单栏中Game/Build XXX Resources 打包资源文件

  5. 打包成功会在项目文件夹中生成StreamingAssets文件夹,目录结构如下:

undefined

注:

  • 红框中为我的打包文件,其他为示例项目打包的资源文件
  • 如果目标平台时Android,需要现在Build Settings中切换平台为安卓,然后再重新生成打包

如果在生成包裹文件后出现以下类似错误:

Assets/Source/LuaWrap/xxxWrap.cs(218,21): error CS1061: Type UnityEngine.xxx' does not contain a definition forxxx' and no extension method xxx' of typeUnityEngine.xxx' could be found (are you missing a using directive or an assembly reference?)
官方给出的解决方案:因为unity不同平台版本api各不相同,因此不是特别统一,遇到此问题直接删除错误代码即可.

4.修改C#脚本

1.PanelManager.cs

Transform Parent {
            get {
                if (parent == null) {
                    GameObject go = GameObject.FindWithTag("Canvas");//原标签为"GuiCamera"
                    if (go != null) parent = go.transform;
                }
                return parent;
            }
        }

因为我的TextFramePanel是直接放在Canvas下的,而原框架中是放在GuiCamera下的,所以我将Canvas添加了一个“Canvas”的标签来作为面板的父物体。

2.AppView.cs

void OnGUI() {
        GUI.Label(new Rect(10, 120, 960, 50), message);

        GUI.Label(new Rect(10, 0, 500, 50), "(1) 单击 \"Lua/Gen Lua Wrap Files\"。");
        GUI.Label(new Rect(10, 20, 500, 50), "(2) 运行Unity游戏");
        GUI.Label(new Rect(10, 40, 500, 50), "PS: 清除缓存,单击\"Lua/Clear LuaBinder File + Wrap Files\"。");
        GUI.Label(new Rect(10, 60, 900, 50), "PS: 若运行到真机,请设置Const.DebugMode=false,本地调试请设置Const.DebugMode=true");
        GUI.Label(new Rect(10, 80, 500, 50), "PS: 加Unity+ulua技术讨论群:>>341746602");
    }

这些是框架的提示信息,可自行修改或删除

3.AppConst.cs

public const bool DebugMode = false;          //调试模式-用于内部测试,默认为true
public const bool UpdateMode = true;          //更新模式-默认为false
public const string WebUrl = "http://192.168.3.9:6688/";  //测试更新地址,默认为localhost

192.168.3.9位本机IP地址

4.HttpServer.cs

修改框架自带的服务器端host地址,即Server/Server.sln中的HttpServer.cs

public HttpServer(int port) {
            host = "http://192.168.3.9:6688/";
        }

5.修改Lua脚本

1.打开项目文件夹

这里可以使用Sublime Text 的 File/Open Folder打开框架中的Lua文件夹,能够清楚的看到文件夹结构。
不过第一次打开也会将所有.meta文件显示出来,显得比较乱,可以参考这里来屏蔽特定文件类型
##2.函数调用顺序
GameManager.cs

        /// <summary>
        /// 资源初始化结束
        /// </summary>
        public void OnResourceInited() {
            LuaManager.Start();
            LuaManager.DoFile("Logic/Network");      //加载游戏
            LuaManager.DoFile("Logic/GameManager");   //加载网络
            initialize = true;  

            NetManager.OnInit();    //初始化网络

            object[] panels = CallMethod("LuaScriptPanel");
            //---------------------Lua面板---------------------------
            foreach (object o in panels) {
                string name = o.ToString().Trim();
                if (string.IsNullOrEmpty(name)) continue;
                name += "Panel";    //添加

                LuaManager.DoFile("View/" + name);
                Debug.LogWarning("LoadLua---->>>>" + name + ".lua");
            }
            //------------------------------------------------------------
            CallMethod("OnInitOK");   //初始化完成
        }

从以上可以看出Lua函数的调用顺序为

GameManager.LuaScriptPanel()-->View/TextFramePanel.lua-->GameManager.OnInitOK()

这里即将控制权交给了Lua文件

3.Logic/GameManger.lua

require "Common/define"
require "Controller/TextFrameCtrl"


GameManager={}
local this = GameManager


function GameManager.LuaScriptPanel()
    return 'TextFrame'
end


function GameManager.OnInitOK()
    AppConst.SocketPort = 2012
    AppConst.SocketAddress = "127.0.0.1"
    NetManager:SendConnect()

    TextFrameCtrl.Awake()
    warn("SimpleFramework start!");
end

4.View/TextFramePanel.lua

local transform
local gameObject

TextFramePanel = {};
local this = TextFramePanel;


function TextFramePanel.Awake(obj)
	-- body
	gameObject = obj
	transform = obj.transform

	this.InitPanel()
end


function TextFramePanel.InitPanel()
	--测试热更新文本
	this.textshow = transform:FindChild("BG/Text").gameObject;
end

5.Controller/TextFrameCtrl.lua

require "Common/define"

local label
local textframe
local transform
local gameObject

TextFrameCtrl = {}
local this = TextFrameCtrl


function TextFrameCtrl.New()
	-- body
	return this
end

function  TextFrameCtrl.Awake()
	-- body
	PanelManager:CreatePanel("TextFrame", this.OnCreate);--创建面板,调用回调函数
end

--启动事件--
function TextFrameCtrl.OnCreate(obj)
	-- body
	gameObject = obj
	transform = obj.transform
	label = TextFramePanel.textshow:GetComponent("Text")

	label.text = "oh, come on man!"
end

6.启动服务器测试

1.Build安卓apk

当服务器没有打开时,打开APK如下图:
undefined

2.启动服务器

以管理员方式启动Server\Server\bin\Debug下的SuperSocket.SocketService.exe
启动后显示图:

undefined

此时再重启APK:

undefined

ok!

如果更新失败可以测试一下手机是否能连接电脑主机端口,即在浏览器中输入 本机IP:端口号
例如:192.168.3.9:6688 输入后能显示下图即连接成功

undefined

如果连接不上可以试试如下方法:
http://jingyan.baidu.com/article/67508eb4dc85e79cca1ce48f.html

7.热更新测试

更新内容:修改文本框中的文字为“更新完成”,并且删除面板中间的那张图片

1.修改Controller/TextFrameCtrl.lua

--启动事件--
function TextFrameCtrl.OnCreate(obj)
	-- body
	gameObject = obj
	transform = obj.transform
	label = TextFramePanel.textshow:GetComponent("Text")

	label.text = "更新完成"
end

2.修改TextFramePanel预制体

将预制体中的图片删除,结构如下:

undefined

然后重新Build Android Resource,重新启动安卓客户端:

undefined

完!