【第三篇】C#調用lua文件


獲取一個全局基本數據類型

  使用LuaEnv.Global.Get<T>("name")就可以    

1 var str = luaEnv.Global.Get<string>("str");
2 var num1 = luaEnv.Global.Get<int>("num1");

 

訪問一個全局table

  方法1. 映射到普通class和sturct

1 -- table
2 gameLanguage={str1 = "C#語言", str2 = "lua語言", str3 = "C++語言"}
    public class GameLanguage
    {
        public string str1;
        public string str2;
        public string str3;
    }

    private void CallLuaTableByClass()
    {
        GameLanguage gameLanguage = luaEnv.Global.Get<GameLanguage>("gameLanguage");
        Debug.Log("[使用類映射]str1: " + gameLanguage.str1);
        Debug.Log("[使用類映射]str2: " + gameLanguage.str2);
        Debug.Log("[使用類映射]str3: " + gameLanguage.str3);
        gameLanguage.str1 = "我是修改后的內容";
        luaEnv.DoString("print('修改后str1的值='..gameLanguage.str1)");
    }

  注釋:

    這個過程是值拷貝,如果class比較復雜代價會比較大(較消耗性能)。而且修改class字段值不會同步到table,反過來也不會。這種方式可以通過把類型添加到GCPotimize生成減低開銷

 

  方法2. 使用interface來進行映射【推薦】

gameUser = {
    name = "XC",
    age = 40,
    ID = "156156156",

    Speak = function()
        print("lua玩家在討論中");
    end,

    Walking = function()
        print("lua玩家在走路中");
    end,

    Calulation = function(this, num1, num2)  --說明:this這里命名可以任意,表示當前對象(即:gameUser)
        return this.age + num1 + num2;
    end,
}
    [CSharpCallLua]
    public interface IGameUser
    {
        string name { get; set; }
        int age { get; set; }
        string ID { get; set; }

        void Speak();
        void Walking();
        int Calulation(int num1, int num2);
    }

    private void CallLuaComplateTableByInterface()
    {
        IGameUser gameUser = luaEnv.Global.Get<IGameUser>("gameUser");

        Debug.Log("[使用接口映射]name: " + gameUser.name);
        Debug.Log("[使用接口映射]age: " + gameUser.age);
        Debug.Log("[使用接口映射]ID: " + gameUser.ID);

        gameUser.Speak();
        gameUser.Walking();
        var result = gameUser.Calulation(2, 4);
        Debug.Log("經過lua計算,結果=" + result);

        gameUser.name = "XCC";
        luaEnv.DoString("print('修改后name的值='..gameUser.name)");
    }

  注釋:

    這種方式依賴於生成代碼(接口需要添加標簽【CSharpCallLua】如果沒生成代碼會拋InvalidCastException異常)get對應table字段,set可以訪問修改lua函數。這種方式為引用拷貝,適合用於復雜表

    

  方法3. 使用Dictionary<key, value> 和 List<>映射簡單表

gameLanguage = {str1 = "C#語言", str2 = "lua語言", str3 = "C++語言"}
gameLanguageList = {"C#語言", "lua語言", "C++語言"}
    private void CallLuaTableByDictionary()
    {
        var dicGameLanguage = luaEnv.Global.Get<Dictionary<string, object>>("gameLanguage"); // 映射一個簡單表

        foreach (string key in dicGameLanguage.Keys)
        {
            Debug.Log("輸出Dictionary中的所有語言" + dicGameLanguage[key]);
        }
    }

    private void CallLuaTableByList()
    {
        var list = luaEnv.Global.Get<List<object>>("gameLanguageList");

        for (int i = 0; i < list.Count; i++)
        {
            Debug.Log("輸出List中的所有語言" + list[i]);
        }
    }

  注釋:這種方式只能映射簡單的表。優點是編寫簡單,效率高。

 

  方法4. 使用LuaTable映射

    private void CallLuaTableByLuaTable()
    {
        var gameUser = luaEnv.Global.Get<LuaTable>("gameUser");

        Debug.Log("name = " + gameUser.Get<string>("name"));
        Debug.Log("age = " + gameUser.Get<int>("age"));
        Debug.Log("ID = " + gameUser.Get<string>("ID"));

        var speak = gameUser.Get<LuaFunction>("Speak");
        speak.Call();

        var walking = gameUser.Get<LuaFunction>("Walking");
        walking.Call();

        var calulation = gameUser.Get<LuaFunction>("Calulation");
        var objArray = calulation.Call(gameUser, 2, 5);
        Debug.Log("輸出結果 = " + objArray[0]);
    }

  注釋:

  這種方式好處是不需要生成代碼,但問題是比較慢(即:效率低)比interface方式慢一個數量級,比如沒有類型檢查

  因為效率低,不推薦常用,適合用在一些很復雜但是使用頻率很低的情況下,能不用就不用。

 

訪問一個全局的function

  方法1. 使用delegage訪問

-- 定義單獨的lua函數
function ProcMyFunc1()
    print("procMyFunc1 無參函數");
end

function ProcMyFunc2(num1, num2)
    print("procMyFunc2 兩個函數 num1+num2="..num1+num2);
end

function ProcMyFunc3(num1, num2)
    print("procMyFunc3 具備返回值的函數");
    return num1+num2;
end

function ProcMyFunc4(num1, num2, num3)
    print("procMyFunc4 三個函數 num1+num2+num3="..num1+num2+num3);
end

function ProcMyFunc5(num1, num2)
    local result = num1+num2;
    print("procMyFunc4 具備多個返回值的函數");
    return num1,num2,result;
end

 

    // 自定義委托
    public delegate void delegateAdding(int num1, int num2);


    private void CallLuaFunctionByDelegage()
    {
        // 使用action直接獲取沒有參數的函數
        var action1 = luaEnv.Global.Get<Action>("ProcMyFunc1");
        action1();

        // 使用自定義委托調用具備兩個輸入參數的函數
        var action2 = luaEnv.Global.Get<delegateAdding>("ProcMyFunc2");
        action2(10, 20);
    }

  多返回值處理方法

  定義全局的delegate

[CSharpCallLua]
public delegate void delegateAddingMultiReturn(int num1, int num2, out int res1, out int res2, out int res3);

[CSharpCallLua]
public delegate void delegateAddingMultiReturnRef(ref int num1, ref int num2, out int res3);
    // 使用delegate訪問多返回值得luafunction
    private void CallLuaFunctionByDelegateMultiReturn()
    {
        // 得到lua中的具有多個返回值的函數(通過委托out關鍵字來進行映射)
        act1 = luaEnv.Global.Get<delegateAddingMultiReturn>("ProcMyFunc5");
        
        // 得到lua中的具有多個返回值的函數(通過委托ref關鍵字來進行映射)
        act2 = luaEnv.Global.Get<delegateAddingMultiReturnRef>("ProcMyFunc5");
        

        // 輸出返回結果
        int intOutRes1 = 0;
        int intOutRes2 = 0;
        int intOutRes3 = 0;
        act1(100, 200, out intOutRes1, out intOutRes2, out intOutRes3);
        Debug.Log(string.Format("res1={0}, res2={1}, res3={2}", intOutRes1, intOutRes2, intOutRes3));
        
        int intResult = 0;
        int intRef1 = 10;
        int intRef2 = 20;
        act2(ref intRef1, ref intRef2, out intResult);
        Debug.Log(string.Format("輸入1={0}, 輸入2={1}, 輸出={2}", intRef1, intRef2, intResult));
    }

  注釋:

  優點:官方推薦方式,性能好,類型安全

  缺點:(含有out與ref關鍵字delegate)要生成代碼(如果沒有生成會拋InvalidCastException異常)

  注意:

  1. 含有out與ref關鍵字委托也需要添加標簽[CSharpCallLua]

  2. 委托引用后,退出luaEnv前,需要釋放委托引用,否則會報錯

  3. 對於Unity與C#中復雜類型API,必須加入xLua的配置文件,經過生成代碼后才能正確使用。例如:Action<int, int, int> 、Func<int, int, int>等

 

  方法2. 使用LuaFunction實現

    private void CallLuaFunctionByLuaFunction()
    {
        var luaFunc1 = luaEnv.Global.Get<LuaFunction>("ProcMyFunc1");
        var luaFunc2 = luaEnv.Global.Get<LuaFunction>("ProcMyFunc2");
        var luaFunc3 = luaEnv.Global.Get<LuaFunction>("ProcMyFunc3");
        // 調用具有多返回數值
        var luaFunc5 = luaEnv.Global.Get<LuaFunction>("ProcMyFunc5");

        luaFunc1.Call();
        luaFunc2.Call(10, 20);

        var result = luaFunc3.Call(10, 20);
        Debug.Log("調用ProcMyFunc3, 結果為:" + result[0]);

        var result5 = luaFunc5.Call(10, 20);
        Debug.Log(string.Format("測試多返回數值 res1={0}, res2={1}, res3={2}", result5[0], result5[1], result5[2]));
    }

  注釋:

  優點:無需生成代碼

  缺點:性能不高,不推薦

  這種方式使用起來很簡單,LuaFcuntion上有個變參的Call函數,可以傳任意類型,任意個數的參數,返回值是object的數組,對應於lua的多返回值

 

官方使用建議:

  1. 訪問lua全局數據,特別是table以及function,代價比較大,建議盡量少做,比如在初始化時把要調用的lua functio獲取一次(映射到delegate)后,保存下來,后續直接調用該delegate即可。table也類似。

  2. 如果lua實現的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦,由一個專門的模塊負責xLua的初始化以及delegate、interface的映射,然后把這些delegate和interface設置到要用到他們的地方

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM