1. 程式人生 > >XLua實現基於MVC框架的熱更新架構

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)[0];
        }

        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;

    }


}