Unity-XLua快速学习

XLua是腾讯研发的Lua开源插件。

github下载地址

Lua文件加载

执行字符串

最基本是直接用LuaEnv.DoString执行一个字符串,字符串得符合Lua语法。

		//定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //lua环境执行语句
            luaenv.DoString("print('hello world!')");
            //释放lua
            luaenv.Dispose();
        }

在这里插入图片描述

加载Lua文件

用lua的require函数即可

//定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //加载lua文件
            luaenv.DoString("require 'byfile'");
        }
        void Update()
        {
            if (luaenv != null)//检测当前luaenv是否为空
            {
                luaenv.Tick();
            }
        }
        void OnDestroy()
        {      
            luaenv.Dispose();//释放lua
        }

byfile.lua.txt文件(lua语法)
在这里插入图片描述

print('hello world')

在这里插入图片描述

自定义Loader

require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。

目前xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是因为Resource只支持有限的后缀,放Resources下的lua文件得加上txt后缀。

//定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //添加自定义Loader方法
            luaenv.AddLoader(MyLoader);
            //加载名为xxx的lua文件
            luaenv.DoString("require 'xxx'");
        }
        //自定义Loader方法
        private byte[] MyLoader(ref string filePath)
        {
            print("调用自定义Loader");
            //找到你想要查找的路径
            string path = Application.dataPath + "/" + "xxx/" + "xxx/"  + filePath + ".lua.txt";
            //通过UTF-8编码读取文件中的内容
            return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
        }
        void OnDestroy()
        {      
            luaenv.Dispose();//释放lua
        }

xxx.lua.txt文件
在这里插入图片描述

print("我是xxx/xxx/xxx.lua")

在这里插入图片描述

C#访问Lua

这里指的是C#主动发起对Lua数据结构的访问。

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

访问LuaEnv.Global就可以了,上面有个模版Get方法,可指定返回的类型。

//定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //加载lua文件
            luaenv.DoString("require 'byfile'");
            //通过c#得到 lua的全局变量
            int a = luaenv.Global.Get<int>("a"); print(a);
            double b = luaenv.Global.Get<double>("b"); print(b);
            string c = luaenv.Global.Get<string>("c"); print(c);
            bool d = luaenv.Global.Get<bool>("d"); print(d);

            luaenv.Dispose();
        }

byfile.lua.txt文件

a = 100
b = 1.11
c = "hello world"
d = true

在这里插入图片描述

访问一个全局的table

映射到普通class或struct

 public class ByFile : MonoBehaviour
    {
        //定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //加载lua文件
            luaenv.DoString("require 'byfile'");
            //通过c#得到 lua的全局变量

            Person p = luaenv.Global.Get<Person>("person");
            print(p.name + "/" + p.age);
            p.name = "lisi";
            luaenv.DoString("print(person.name)");
            luaenv.Dispose();
        }
    }
    class Person
    {
        public string name;
        public int age;
    }

byfile.lua.txt文件

person = {
	name = "zhangsan",
	age = 18,
}

在这里插入图片描述

映射到一个interface

这种方式依赖于生成代码(如果没生成代码会抛InvalidCastException异常),代码生成器会生成这个interface的实例,如果get一个属性,生成代码会get对应的table字段,如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数。

public class ByFile : MonoBehaviour
    {
        //定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //加载lua文件
            luaenv.DoString("require 'byfile'");
            //通过c#得到 lua的全局变量

            IPerson p = luaenv.Global.Get<IPerson>("person");
            print(p.name + "/" + p.age);
            p.name = "lisi";
            luaenv.DoString("print(person.name)");
            p.eat();
            p.add(10 , 20);
            luaenv.Dispose();
        }
    }

    [CSharpCallLua]
    public interface IPerson
    {
        string name { get; set; }
        int age { get; set; }
        void eat();
        void add(int a, int b);
    }

byfile.lua.txt文件

person = {
	name="zhangsan",
	age=18,
	eat=function()
		print("我正在吃饭");
	end
}

function person:add(a,b)--默认带一个self参数,代表当前table等价c#里的this
	print(a+b)
end
--[[
function person.add(self,a,b)
	print(a+b)
end
--]]

在这里插入图片描述
踩坑经历,由于版本不兼容问题,这里加上[CSharpCallLua],并不是所有版本会自动生成代码,每次对byfile.lua.txt文件进行修改需要,右键项目,在这里插入图片描述
进行代码清理,回到unity 点击XLua菜单 Clear Generated code,再点击Generate code,运行即可。

如果上述方法还不成功,请在需要[CSharpCallLua]的方法或委托等,在前面添加public。

更轻量级的by value方式:映射到Dictionary<>,List<>

byfile.lua.txt文件

person = {
	name="zhangsan",
	age=18,
	eat=function()
		print("我正在吃饭");
	end
	,1,2,3,4,1.1,3.2,"student",true,
}

function person:add(a,b)--默认带一个self参数,代表当前table等价c#里的this
	print(a+b)
end
Dictionary<string, object> dic = luaenv.Global.Get<Dictionary<string, object>>("person");
foreach (string key in dic.Keys)
{
   print(key + "==" + dic[key]);
}

在这里插入图片描述

List<object> list = luaenv.Global.Get<List<object>>("person");
foreach (object o in list)
{
   print(o);
}

在这里插入图片描述

另外一种by ref方式:映射到LuaTable类

LuaTable tab = luaenv.Global.Get<LuaTable>("person");
print(tab.Get<string>("name"));

在这里插入图片描述

访问一个全局的function

写完代码,需要回到unity 点击XLua菜单 点击Generate code,运行即可。

Action<int,int> act1 = luaenv.Global.Get<Action<int,int>>("Sum");
act1(10,20);
act1 = null;

byfile.lua.txt文件

function Sum(a,b)
	print("调用Sum函数");
	print(a+b);
	return a+b;
end

在这里插入图片描述

映射到delegate

这种是建议的方式,性能好很多,而且类型安全。缺点是要生成代码(如果没生成代码会抛InvalidCastException异常)。

delegate要怎样声明呢?
对于function的每个参数就声明一个输入类型的参数。

多返回值要怎么处理?从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数。

参数、返回值类型支持哪些呢?都支持,各种复杂类型,out,ref修饰的,甚至可以返回另外一个delegate。

delegate的使用就更简单了,直接像个函数那样用就可以了。

public class ByFile : MonoBehaviour
    {
        //定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            //加载lua文件
            luaenv.DoString("require 'byfile'");

            Sum act1 = luaenv.Global.Get<Sum>("Sum");
            int resa; int resb;
            int res = act1(10, 20, out resa, out resb);
            print(res);print(resa);print(resb);//返回多个值
            act1 = null;

            luaenv.Dispose();
        }
    }
    
    [CSharpCallLua]
    public delegate int Sum(int a, int b, out int c, out int d);

byfile.lua.txt文件

function Sum(a,b)
	print("调用Sum函数");
	print(a+b);
	return a+b,a,b;
end

在这里插入图片描述

映射到LuaFunction

这种方式的优缺点刚好和第一种相反。

使用也简单,LuaFunction上有个变参的Call函数,可以传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。

LuaFunction luaFunction = luaenv.Global.Get<LuaFunction>("Sum");
object[] os = luaFunction.Call(10, 20);
foreach (object o in os)
{
     print(o);
}

在这里插入图片描述
提示

1、访问lua全局数据,特别是table以及function,代价比较大,建议尽量少做,比如在初始化时把要调用的lua function获取一次(映射到delegate)后,保存下来,后续直接调用该delegate即可。table也类似。

2、如果lua测的实现的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一个专门的模块负责xlua的初始化以及delegate、interface的映射,然后把这些delegate和interface设置到要用到它们的地方。

Lua调用C#

//定义一个lua环境的全局变量
        LuaEnv luaenv = null;
        void Start()
        {
            luaenv = new LuaEnv();
            luaenv.DoString("require 'byfile'");
            luaenv.Dispose();
        }

new C#对象

--构造游戏物体, new对象
CS.UnityEngine.GameObject("new by lua")

在这里插入图片描述

访问C#静态属性,方法

--读静态属性
print(CS.UnityEngine.Time.deltaTime)
--写静态属性
CS.UnityEngine.Time.timeScale = 0.5

local gameObject = CS.UnityEngine.GameObject
--调用静态方法
local camera = gameObject.Find("Main Camera")
--更改摄像机名称
camera.name = "update by lua"

在这里插入图片描述
在这里插入图片描述
小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能

访问C#成员属性,方法

--构造游戏物体, new对象
--CS.UnityEngine.GameObject("new by lua")
--读静态属性
print(CS.UnityEngine.Time.deltaTime)
--写静态属性
CS.UnityEngine.Time.timeScale = 0.5

local gameObject = CS.UnityEngine.GameObject
--调用静态方法
local camera = gameObject.Find("Main Camera")
--更改摄像机名称
camera.name = "update by lua"

--调用成员方法的时候 ,使用冒号
local cameraCom= camera:GetComponent("Camera")
--否则需要把自己当做第一个参数传递
--local cameraCom= camera.GetComponent(camera,"Camera")
--删除Camera组件
gameObject.Destroy(cameraCom)

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值