(XLua)C#与Lua中的交互

XLua下载地址:https://github.com/Tencent/xLua

Paste_Image.png

下载后接下来就是导入XLua到unity里了,解析出来的XLua有下面几个文件夹


Paste_Image.png

我们只需要将Assests:主目录里面的东西全部导入到Unity里面就OK了,导入后再XLua的文件夹下有这么几个。里面都有学习的文档,也可自行去学。


Paste_Image.png
hotfix的环境配置

在unity的PlayerSetting下的Other Settings里面打开XLua的宏HOTFIX_ENABLE,只有打开这个宏以后才能进行Xlua的修复以及更新

image.png
然后我们打开工程中XLua例子中的第八个例子08_Hotfix看看是如何配置的
image.png

定义后后生成代码并注入
image.png
如有报错请看注意事项
使用建议
对所有较大可能变动的类型加上[Hotfix]标识;
建议用反射找出所有函数参数、字段、属性、事件涉及的delegate类型,在C#函数中调用Lua,在C#函数上标注[CSharpCallLua]
业务代码、引擎API、系统API,需要在Lua补丁里头高性能访问的类型,在Lua中调用C#函数,在C#函数上标注加上[LuaCallCSharp]
引擎API、系统API可能被代码剪裁调(C#无引用的地方都会被剪裁),如果觉得可能会新增C#代码之外的API调用,这些API所在的类型要么加LuaCallCSharp,要么加ReflectionUse;
开发过程:
首先开发业务代码->在所有可能出现问题的类上打上hotfix的标签,在所有lua调用CSharp的方法上打上LuaCallCSharp,在所有CSharp调用Lua的方法上打上CSharpCallLua->打包发布->修改bug时只需要更新Lua文件,修改资源时(声音,模型,贴图,图片,UI)只需要更新ab包。用户只需要去下载lua文件跟ab包。

C#访问Lua中的全局变量与table

首先创建一个在Resources下面创建一个文本文件并给其命名为Hello world.lua.txt,这样我们就可以读取到Lua文本文件了,然后写入以下

print("hello world from file")
a=100
Str="NiHao"
IsDie=false

person=
{
name="Tao",age=20,

eat=function(self,a,b)     --一个函数 self代表自身  隐藏参数  后面再跟两个int参数
print(a+b)
print("OK")
end
}

接着我们创建一个脚本HolloworldXLua引入程序集XLua在Start方法下写入

一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
DoString参数为String,可输入任意合法的Lua代码.

using UnityEngine;
using XLua;

public class HolloworldXLua: MonoBehaviour {

    // Use this for initialization
    void Start () {
        LuaEnv luaenv = new LuaEnv();//一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
        luaenv.DoString("require 'Hello world'");//通过内置的Loder加载lua源文件
        int a = luaenv.Global.Get<int>("a");//获取到Lua里面的全局变量a
        Debug.Log(a);
        string Str = luaenv.Global.Get<string>("Str");
        Debug.Log(Str);
        bool IsDie = luaenv.Global.Get<bool>("IsDie");
        Debug.Log(IsDie);

        //Person p = luaenv.Global.Get<Person>("person");
        IPerson p = luaenv.Global.Get<IPerson>("person");
        Debug.Log(p.name+p.age);
        p.eat(12,22);//调用Lua里面的函数  p.eat(p,12,22)有隐藏参数

        luaenv.Dispose();
    }
    class Person
    {
        public string name;
        public int age;  
    }

    //获取Lua里面的列表用接口也可以映射的,但是要加上CSharpCallLua
    [CSharpCallLua]
    interface IPerson
    {
        string name { get; set; }
        int age { get; set; }
        void eat(int a,int b);
    }

}

在这里访问Lua中的Table有几种方法一种是映射到类中,另一种是映射到接口中去,但是这两种方法结果都是相同但是,有一点是不一样的,那就是映射到类中只拷贝Lua里面的数据但是用接口映射的话可以修改Lua里面的数据.,用接口相当与引用
然后我们就可以看到输出的结果,输出的就是Lua脚本里面的全局变量与里面的table里面的


Paste_Image.png

然后还可以通过Dictionary或者List去映射Lua表里面的数据

   void Start()
    {
        LuaEnv luaenv = new LuaEnv();//一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
        luaenv.DoString("require 'Hello world'");//通过内置的Loder加载lua源文件

        Dictionary<string, object> dict = luaenv.Global.Get<Dictionary<string, object>>("person");//person表示哪个表
        foreach (string Key in dict.Keys)
        {
            print(Key + ":" + dict[Key]);
        }
        luaenv.Dispose();
    }

输出结果:


Paste_Image.png

下面使用List也可以映射那些没有Key的值,
Lua脚本里面

print("hello world from file")
a=100
Str="NiHao"
IsDie=false

person=
{
name="Tao",age=20,2,2,212,15
}
function person:eat(a,b)
   print(a+b)
end 

C#脚本里面

    void Start()
    {
        LuaEnv luaenv = new LuaEnv();//一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
        luaenv.DoString("require 'Hello world'");//通过内置的Loder加载lua源文件

  
        List<object> list = luaenv.Global.Get<List<object>>("person");//person表示哪个表
        foreach (object o in list)
        {
            print(o);
        }
        luaenv.Dispose();
    }

最后输出可以看到2输出两次212和15分别输出一次对应Lua脚本里面的数据:


Paste_Image.png

还有一种访问Tab的方式就是使用LuaTable,这种方式不推荐使用,性能比较慢,我推荐使用第二种方式通过去创建Intaface去映射Lua中的Table。

访问一个全局的Function

首先Lua脚本里面写入函数方法,一个有多个返回值有参数的方法

function add(a,b)
     print(a+b)
     return a+b,a,b
  end

那么在C#中如何去调用呢下面来看看,因为我们在C#中只能有一个返回值而在Lua中可以有多个返回值,那么在C#返回值的时候只能返回第一个值,而Lua后面的返回值可以在C#中用out或者ref去接收后面的返回值

    [CSharpCallLua]
    delegate int Add(int a, int b,out int resa,out int resb);//定义一个有返回值有参数的委托
    void Start()
       {
        LuaEnv luaenv = new LuaEnv();//一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
        luaenv.DoString("require 'Hello world'");//通过内置的Loder加载lua源文件
        Add add = luaenv.Global.Get<Add>("add");
        int resa, resb;
        int res=add(12,15,out resa,out resb);
        print(res);
        print(resa);
        print(resb);
        add = null;//Action有映射如果直接释放Lua虚拟机的话直接会报错只有将Action函数置空后才能释放虚拟机
        luaenv.Dispose();
    }

输出结果,前面两个是Lua里面输出的,后面是C#里面输出的,这样就轻松调用了Lua里面的方法了


Paste_Image.png

还有一种方式就是使用Lua自带的LuaFction,和上面LuaTable使用一样比较耗费性能,但是使用简单所以这里也不推荐使用

添加自定义Load的方法

如果我们的Lua文本不想放在Resource里面加载想放到其他地方加载怎么办呢,Xlua也提供了自定义的Load方法,比如我们想把我们的Lua脚本放在StreamingAssets文件夹下面,那么该如何做呢,首先先在Unity里面创建一个StreamingAssets文件夹,然后把我们的Lua脚本放在StreamingAssets文件夹下,创建一个脚本CreateLoade,写入代码

    private LuaEnv luaenv;
    // Use this for initialization
    void Start () {
        luaenv = new LuaEnv();

        luaenv.AddLoader(MyLoader);//添加自己的Load

        luaenv.DoString("require 'hello world'");
    }

    private byte[] MyLoader(ref string filePath)
    {
        // Application.streamingAssetsPath表示找到Asses里面的StreamingAssets
        string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";

        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath)); ;
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

然后我们在Unity里面运行起来看结果,输出了Lua脚本里输出的结果。这样就没问题了.


Paste_Image.png

在Lua中构造Unity里面游戏物体并且查找游戏对象获取相应组件

在Lua脚本中写入

--构造游戏物体,New一个对象
CS.UnityEngine.GameObject("NewByLua")

--访问静态属性
print(CS.UnityEngine.Time.deltaTime)

--局部变量 访问Unity里面的游戏物体
local gameobject=CS.UnityEngine.GameObject
local camera=gameobject.Find("Main Camera")
local light=gameobject.Find("Directional Light")
light.name="UpdataLight"

--获取light游戏物体里面的Light组件 调用成员方法的时候,使用冒号
local lightCom=light:GetComponent("Light")

--销毁lightCom组件
gameobject.Destroy(lightCom)

这时候C#中构造虚拟机运行的时候就会在Unity里面构造一个空的游戏物体,运行后会生成一个名为NewByLua的空游戏物体,并且会查找到Directional Light并修改名为为UpdataLight,并移除了里面的Light组件


Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,478评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,825评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,482评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,726评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,633评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,018评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,168评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,320评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,264评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,288评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,995评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,587评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,909评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,284评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,862评论 2 339

推荐阅读更多精彩内容