1. 程式人生 > >XLua遇坑總結(不定期更)

XLua遇坑總結(不定期更)

1.NGUI通過lua層為按鈕設定lua中點選回撥方法時,需要把儲存當前回撥事件的指令碼記錄到list中,並在該LuaEnv Dispose()之前將所有onClick = null,否則會導致xlua丟擲”try to dispose a LuaEnv with C# callback!” 異常
參考連結:http://www.cnblogs.com/ghl_carmack/p/7350530.html

參考程式碼:

private List<UIEventListener> ButtonEventListener = new List<UIEventListener>();

///
<summary>
/// 新增單擊事件 /// </summary> public void AddClick(GameObject go,UIEventListener.VoidDelegate luafunc) { if (go == null || luafunc == null) return; UIEventListener uievent = UIEventListener.Get(go); uievent.onClick = delegate(GameObject o) { luafunc(go); }; ButtonEventListener.Add(uievent); } ///
<summary>
/// 清除單擊事件 /// </summary> public void ClearClick() { foreach (var listener in ButtonEventListener) { listener.onClick = null; } ButtonEventListener.Clear(); } void OnDestroy() { ClearClick() ; luaEnvironment.Dispose(); }

2.C# Call Lua 時的面向物件
(每個c#指令碼對應一個lua檔案,並且會重名)
lua中初始化程式碼如下:

Skill_10101 =
{
    skillObj = 0
}

-- 這句是重定義元表的索引,就是說有了這句,這個才是一個類。
Skill_10101.__index = Skill_10101

-- 構造體,構造體的名字是隨便起的,習慣性改為New()
function Skill_10101:New(sObj)
    local self = { };
    -- 初始化self,如果沒有這句,那麼類所建立的物件改變,其他物件都會改變
    setmetatable(self, Skill_10101);
    -- 將self的元表設定為Class
    self.skillObj = sObj;
    return self;
end

當c#指令碼初始化時讀取對應lua檔案,程式碼如下:

    public static string LuaStr = "Skill_";
    public string LuaName { get { return LuaStr + this.SkillMode.dataBase.id; } }
    // 對應該lua檔案    
    private LuaTable _luaSkill = null;
    // 對應該lua New出來的物件
    private LuaTable _luaTableObject;
    public LuaTable LuaTable
    {
        get
        {
            if (_luaSkill == null && _isExistLuaFile)
            {
                try
                {
                    ManagerUtil.LuaManager.RequireFile("Skill/" + LuaName);
                    _luaSkill = ManagerUtil.LuaManager.GlobleLuaEnvTable.Get<LuaTable>(LuaName);
                    //如果讀取失敗,說明不存在這個lua技能 擇全部跳過
                    _isExistLuaFile = _luaSkill != null;
                    if (_isExistLuaFile)
                    {
                        // New一個luaTable物件 並在c# call lua 方法時將該物件傳入第一個引數
                        var tab = _luaSkill.Get<LuaFunction>("New").Call(_luaSkill, this);
                        _luaTableObject = (LuaTable) tab[0];
                    }
                }
                catch
                {
                    _isExistLuaFile = false;
                }

            }
            return _luaSkill;
        }
    }

/// 回撥lua中程式碼
/// 可以理解為從一個class中查詢到該成員方法
/// 然後使用該class提前new出的物件呼叫該成員方法
public void CallLuaFunction(string FunName)
{
    if (this.LuaTable != null)
    {
       var func = this.LuaTable.Get<LuaFunction>(funcName);
       if (func != null)
       {
           func.Call(_luaTableObject);
       }
    }
}

3.C#呼叫lua傳遞引數問題
之前專案用ToLua時候,C#呼叫lua中的方法可以交給C#中的LuaManager讀取lua方法,對應的lua引數是以params object[]形式傳遞進來的,但是換了xlua以後,必須直接將引數傳遞給LuaFunction呼叫,也就是說不允許在C#層將引數二次裝箱處理,否則lua中只能讀取出一個引數,並且為userdata型別.

// ToLua:
// 該方法寫在lua管理類即可,其他C#指令碼直接呼叫該方法
// 傳遞進的引數裝箱為params object[]形式 再次傳入LuaFunction
public void CallLuaFunction(string FunName,params object[] args)
{
    if (this.LuaTable != null)
    {
       var func = this.LuaTable.Get<LuaFunction>(funcName);
       if (func != null)
       {
           func.Call(_luaTableObject,args);
       }
    }
}


// XLua:
// 在每個呼叫lua方法的C#指令碼中單獨寫出對應方法
// 由LuaFunction做裝箱操作,直接傳入params object[]型引數lua會讀取錯誤
public void CallLuaFunction(string FunName,GameObject obj)
{
    if (this.LuaTable != null)
    {
       var func = this.LuaTable.Get<LuaFunction>(funcName);
       if (func != null)
       {
           func.Call(_luaTableObject,obj);
       }
    }
}