【第三篇】C#调用lua文件 第三卷第十三部分

   2023-02-09 学习力0
核心提示:获取一个全局基本数据类型  使用LuaEnv.Global.GetT("name")就可以    1 var str = luaEnv.Global.Getstring("str");2 var num1 = luaEnv.Global.Getint("num1"); 访问一个全局table  方法1. 映射到普通class和sturct1 -- table2 gameLanguage={str1

获取一个全局基本数据类型

  使用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设置到要用到他们的地方

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • LUA解析json小demo
    需要修改的json数据gui-config.json{"configs": [{"server": "JP3.ISS.TF","server_port": 443,"password": "58603228","method": "aes-256-cfb","remarks": ""},{"serv
    03-16
  • 第二十三篇:在SOUI中使用LUA脚本开发界面
    像写网页一样做客户端界面可能是很多客户端开发的理想。做好一个可以实现和用户交互的动态网页应该包含两个部分:使用html做网页的布局,使用脚本如vbscript,javascript做用户交互的逻辑。当需求变化时,只需要在服务端把相关代码调整一下,用户即可看到新的
    03-16
  • windows下编译lua源码"><转>windows下编译lua源
    因为之前一直使用 lua for windows 来搭建lua的使用环境,但是最新的 lua for windows 还没有lua5.2,我又想用这个版本的lua,所以被逼无奈只能自己编一下lua源码。首先从 lua的官网 下载你想要使用的lua源码,比如我下载的就是lua5.2。解压后内容如下:
    03-16
  • lua:使用Lua处理游戏数据
    在之前lua学习:lua作配置文件里,我们学会了用lua作配置文件。其实lua在游戏开发中可以作为一个强大的保存、载入游戏数据的工具。 比如说,现在我有一份表单:data.xls用什么工具解析这个Excel文件并将数据载入游戏?我们可以使用Lua来完成这个工作。不过要
    03-16
  • 第1课 - 学习 Lua 的意义
    第1课 - 学习 Lua 的意义
    第1课 - 学习 Lua 的意义1.Lua 简介           (1) 1993年、巴西(2) 小巧精致的脚本语言,大小只有 200K(3) 用标准C语言写成,能够在所有的平台上编译运行(4) 发明的目标是嵌入在C/C++中,为应用程序提供灵活的扩展和定制功能(5) 不适合用于开发
    03-16
  • RedisTemplate 常用API+事务+陷阱+序列化+pipeline+LUA
    RedisTemplate 常用API+事务+陷阱+序列化+pipel
    https://www.jianshu.com/p/7bf5dc61ca06/https://blog.csdn.net/qq_34021712/article/details/79606551https://www.jianshu.com/p/c9f5718e58f0dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/depe
    03-08
  • Nginx动态路由的新姿势:使用Go取代lua nginx路由规则
    Nginx动态路由的新姿势:使用Go取代lua nginx路
    导语: 在Nitro 中, 我们需要一款专业的负载均衡器。 经过一番研究之后,Mihai Todor和我使用Go构建了基于Nginx、Redis 协议的路由器解决方案,其中nginx负责所有繁重工作,路由器本身并不承载流量。 这个解决方案过去一年在生产环境中运行顺畅。 以下是我
    03-08
  • cocos2d-lua 控制台输入Lua指令方便调试
    用脚本进行开发,如果不能实时去输入指令,就丧失了脚本的一大特色,所以对cocos2d-x程序稍微修改下,使其可以直接从控制台读入lua指令,方便调试。1 首先在行首加入lua的引用,如下1 #include "main.h"2 #include "AppDelegate.h"3 #include "cocos2d.h"4 #i
    02-09
  • lua_touserdata
    void *lua_touserdata(lua_State*L,intindex);如果给定索引处的值是一个完整的userdata,函数返回内存块的地址。如果值是一个lightuserdata,那么就返回它表示的指针。否则,返回NULL。例如: 在CCLuaStack::executeFunction()函数中有一段代码是用来获取c++
    02-09
  • Lua 5.2 中文参考手册
    闲来无事,发现Lua更新到了5.2.2,参考手册也更到了5.2,在网上发现只有云风翻译的5.1版,花了几天时间翻译了一些。参考手册有点长,又要随时修改,所以在github上建了项目,有需要的朋友可以看看,同时也欢迎指正。中文手册:Lua 5.2中文参考手册
    02-09
点击排行