天天看点

XLua实现基于MVC框架的热更新架构

1、将XLua的包导入工程

2 -1、编写程序的主入口脚本GameMgr、用于启动Lua程序

`public class GameMgr : MonoBehaviour {

private void Awake()
{
    gameObject.AddComponent<LuaMgr>();
}

private void Start()
{
    LuaMgr.Instance.DoString("require 'Script/Xlua/XLuaFrame/Common/Main'");
}
           

}`

2 - 2 编写LuaMgr脚本、用于实例化全局唯一的Lua环境变量、并且加载所有的lua脚本

`

public class LuaMgr : MonoBehaviour {

public static LuaMgr Instance;

public static LuaEnv luaEnv;


private void Awake()
{
    DontDestroyOnLoad(this);
    Instance = this;
    luaEnv = new LuaEnv();

    //设置xlua脚本的路径   路径根据实际需求修改
    luaEnv.DoString(string.Format("package.path = '{0}/?.lua'", Application.dataPath));

}

public void DoString(string str)
{
    luaEnv.DoString(str);
}
           

}

`

3、Main.lua — 寻找到GameInit的脚本、执行初始化Init操作。开始初始化lua脚本

require "Script/Xlua/XLuaFrame/Common/GameInit"  -- require 寻找到GameInit.lua脚本的引用

GameInit.Init();
           

4-1 GameInit.Lua 脚本、初始化所有的View脚本、同事提供加载Ctrl脚本的方法

require "Script/Xlua/XLuaFrame/Common/CtrlMgr"; 
 -- CtrlMgr.lua  管理控制器脚本、里面table 表存储其名字及其对应的ctrl脚本的实例 --
GameInit = {};
local this = GameInit;

-- 将View的脚本一一注册进去
function GameInit.InitViews()
        require('Script/Xlua/XLuaFrame/Modules/UIRoot/UIRootView');
end

--初始化方法 ctrl 和 view 同时加载root界面
function GameInit.Init()
    this.InitViews();
    CtrlMgr.Init();
    GameInit.loadView(CtrlNames.UIRootCtrl);
end

--从控制器中拿出一个来调用它的Awake方法 加载窗体--
function GameInit.loadView(type)
    local ctrl = CtrlMgr.GetCtrl(type);
    if ctrl ~= nil then
        ctrl.Awake();
    end
end
           

4-2 CtrlMgr.lua 脚本 初始化所有的控制器脚本、存储到table表中

require "Script/Xlua/XLuaFrame/Common/Define"

--注册UI控制器 (动态添加)------------------
require "Script/Xlua/XLuaFrame/Modules/UIRoot/UIRootCtrl"

CtrlMgr = {};

local this = CtrlMgr;

local ctrlList = {};

--初始化方法 往列表中添加所有的控制器
function CtrlMgr.Init() 
    -- 注册控制器到table表中(动态添加)------------------
    ctrlList[CtrlNames.UIRootCtrl] = UIRootCtrl.New();

    return this;
end


--根据控制器的名称 获取控制器
function CtrlMgr.GetCtrl(ctrlName)
    return ctrlList[ctrlName];
end
           

5、Define.lua 提供公共的变量、及其反射unity中的api到Lua中`print(‘启动了Define.lua’)

-- 没新加一个窗口、要在该脚本添加该窗口的引用  同事在CtrlMgr.lua中注册该窗口  GameInit.lua中注册它对应的View视图脚本

CtrlNames=
{
    UIRootCtrl = "UIRootCtrl"
}



--这里要把常用的引擎类型加起来
WWW = CS.UnityEngine.WWW;
GameObject = CS.UnityEngine.GameObject;
Color = CS.UnityEngine.Color;
Vector3 = CS.UnityEngine.Vector3;`
           

6 提供Lua中Ctrl 和 View的两个模板实例、所有脚本都应该已此为模板

View 脚本主要用于查找组件、反射Unity中的脚本生命周期方法

UIRootView = {};
local this = UIRootView;

local transform;  -- 自身的transform引用
local gameobject; -- 自身的gameobject引用


function UIRootView.awake(obj)

    gameobject = obj;
    transform = obj.transform;
    this.InitView();
end


--初始化面板  找到UI组件
function UIRootView.InitView()

    --寻找组件  
    this.btnOpenTask = transform:FindChild("Bg/btnOpenTask"):GetComponent("UnityEngine.UI.Button");
end

function UIRootView.start()

end

function UIRootView.update()

end

function UIRootView.ondestory()

end
           

Ctrl脚本 主要用于控制UI的加载、显示、事件的点击回调

UIRootCtrl = {};
local this = UIRootCtrl;

local root;
local transform;
local gameobject;

function UIRootCtrl.New()
    return this;
end

function UIRootCtrl.Awake()
    print('主界面、启动了');

    --这里的方法就是负责把UI给克隆出来  遇到方法时 使用 : 加上后面的方法
    CS.LuaHelperManager.Instance:LoadUI("XluaPrefab/UIRootView",this.OnCreate);
    --CS.LuaHelperManager 去调用Unity中的LuaHelperManager脚本中的方法加载UI及其回调
end


-- Awake加载UI的回调(返回克隆的obj对象)
function UIRootCtrl.OnCreate(obj)
    print('UI克隆完毕的回调');

    local btnOpenTask = UIRootView.btnOpenTask;
    btnOpenTask.onClick:AddListener(UIRootCtrl.OnBtnOpenTaskClick);
end

-- 按钮点击的方法
function UIRootCtrl.OnBtnOpenTaskClick()

end
           

以上已经说了怎么Lua中的架构搭建、那么怎么将Unity中的生命周期给lua调用呢?

7、Lua调用C#中的方法加载UI窗体

//Lua中调用该C#脚本  运行前XLua  Generate Code 运行一下
[LuaCallCSharp]
public class LuaHelperManager 
{

    protected static LuaHelperManager mInstance;

    protected LuaHelperManager(){ }

    public static LuaHelperManager Instance
    {
        get
        {
            if (mInstance == null)
            {
                mInstance = new LuaHelperManager();
            }
            return mInstance;
        }
    }


    /// <summary>
    /// Xlua层加载UI面板
    /// </summary>
    /// <param name="path"> 路径 </param>
    /// <param name="OnCreate"> 创建出来的委托回调 </param>
    public void LoadUI(string path,XLuaCustomExport.OnCreate OnCreate)
    {
        Debug.Log("加载UI窗体 ==" + path);
        GameObject obj =  GameObject.Instantiate(Resources.Load<GameObject>(path));
        if (OnCreate != null)
        {
            obj.GetOrAddCompent<LuaViewBehaviour>();
            OnCreate(obj);
        }

    }


}



/// <summary>
/// XLua的自定义拓展
/// </summary>
public static class XLuaCustomExport  {

    [CSharpCallLua]
    public delegate void OnCreate(GameObject obj);
}


           

8 加载出来的UI窗体Panel挂载上LuaViewBehaviour脚本、同事将Unity中的脚本生命周期方法回调给Unity

public class LuaViewBehaviour:MonoBehaviour {

    [CSharpCallLua]
    public delegate void delLuaAwake(GameObject obj);
    LuaViewBehaviour.delLuaAwake luaAwake;

    [CSharpCallLua]
    public delegate void delLuaStart();
    LuaViewBehaviour.delLuaStart luaStart;

    [CSharpCallLua]
    public delegate void delLuaUpdate();
    LuaViewBehaviour.delLuaUpdate luaUpdate;

    [CSharpCallLua]
    public delegate void delLuaOnDestroy();
    LuaViewBehaviour.delLuaOnDestroy luaOnDestroy;



    private LuaTable scriptEnv;  
    private LuaEnv luaEnv;


    private void Awake()
    {
        //获取全局的Lua环境变量
        luaEnv = LuaMgr.luaEnv;

        scriptEnv = luaEnv.NewTable();

        LuaTable meta = luaEnv.NewTable();
        meta.Set("__index",luaEnv.Global);
        scriptEnv.SetMetaTable(meta);
        meta.Dispose();

        string prefabName = name;
        //去掉克隆的关键字
        if (prefabName.Contains("(Clone)"))
        {
            prefabName = prefabName.Split(new string[] { "(Clone)" }, StringSplitOptions.RemoveEmptyEntries)[];
        }

        prefabName = prefabName.Replace("pan_", "");

        //  prefabName + ".awake"  要对应Lua脚本中View的方法
        luaAwake = scriptEnv.GetInPath<LuaViewBehaviour.delLuaAwake>(prefabName + ".awake");
        luaStart = scriptEnv.GetInPath<LuaViewBehaviour.delLuaStart>(prefabName + ".start");
        luaUpdate = scriptEnv.GetInPath<LuaViewBehaviour.delLuaUpdate>(prefabName + ".update");
        luaOnDestroy = scriptEnv.GetInPath<LuaViewBehaviour.delLuaOnDestroy>(prefabName + ".ondestroy");

        scriptEnv.Set("self", this);
        if (luaAwake != null)
        {
            luaAwake(this.gameObject); 
        }


    }




    private void Start()
    {

        if (luaStart != null)
        {
            luaStart();
        }
    }




    private void OnDestroy()
    {
        if (luaOnDestroy != null)
        {
            luaOnDestroy();
        }
        luaAwake = null;
        luaOnDestroy = null;
        luaUpdate = null;
        luaStart = null;

    }


}