xlua官方Examples例子学习

xlua官方Examples例子学习,第1张

文章目录
  • 一 Hello World例子 执行字符串
  • 二 执行lua文件,C#与lua交互
  • 三 UI绑定与交互
  • 四 通过元表,实现lua面向对象
  • 五 NoGC Lua访问C#函数无gc

一 Hello World例子 执行字符串
namespace XLuaTest
{
    public class Helloworld : MonoBehaviour
    {
        void Start()
        {
            LuaEnv luaenv = new LuaEnv();
            luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
            luaenv.Dispose();
        }
    }
}

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

二 执行lua文件,C#与lua交互

C#文件 LuaBehaviour.cs

namespace XLuaTest
{
    [System.Serializable]
    public class Injection
    {
        public string name;
        public GameObject value;
    }
    //xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置
    //比如你想从lua调用c#的某个类,希望生成适配代码
    //你可以为这个类型打一个LuaCallCSharp标签
    [LuaCallCSharp]
    public class LuaBehaviour : MonoBehaviour
    {
        public TextAsset luaScript;
        public Injection[] injections;
 		//所有lua共享这一个luaenv!
        internal static LuaEnv luaEnv = new LuaEnv();
        
        internal static float lastGCTime = 0;
        internal const float GCInterval = 1;//1 second 

        private Action luaStart;
        private Action luaUpdate;
        private Action luaOnDestroy;

        private LuaTable scriptEnv;

        void Awake()
        {
            scriptEnv = luaEnv.NewTable();

            // 为每个脚本设置一个独立的环境
            // 可一定程度上防止脚本间全局变量、函数冲突
            LuaTable meta = luaEnv.NewTable();
            meta.Set("__index", luaEnv.Global);
            scriptEnv.SetMetaTable(meta);
            meta.Dispose();
			//设置lua中self为当前C#中的this,方便对当前对象进行 *** 作
            scriptEnv.Set("self", this);
            //设置lua中通过name来获取GameObject
            foreach (var injection in injections)
            {
                scriptEnv.Set(injection.name, injection.value);
            }
			// 加载luaScript变量上挂载的lua,别名为LuaTestScript
			// 加载到scriptEnv表中
            luaEnv.DoString(luaScript.text, "LuaTestScript", scriptEnv);

			// C#访问lua中的方法
			// 注意:通常是用luaenv.Global.Get访问全局方法
			// 这里是之前设置了元表,meta.Set("__index", luaEnv.Global);
            Action luaAwake = scriptEnv.Get<Action>("awake");
            scriptEnv.Get("start", out luaStart);
            scriptEnv.Get("update", out luaUpdate);
            scriptEnv.Get("ondestroy", out luaOnDestroy);

            if (luaAwake != null)
            {
                luaAwake();
            }
        }

        // Use this for initialization
        void Start()
        {
            if (luaStart != null)
            {
                luaStart();
            }
        }

        // Update is called once per frame
        void Update()
        {
            if (luaUpdate != null)
            {
                luaUpdate();
            }
            if (Time.time - LuaBehaviour.lastGCTime > GCInterval)
            {
                luaEnv.Tick();
                LuaBehaviour.lastGCTime = Time.time;
            }
        }

        void OnDestroy()
        {
            if (luaOnDestroy != null)
            {
                luaOnDestroy();
            }
            luaOnDestroy = null;
            luaUpdate = null;
            luaStart = null;
            scriptEnv.Dispose();
            injections = null;
        }
    }

lua文件 LuaTestScript.lua

local speed = 10
local lightCpnt = nil
function start()
	print("lua start...")
	** 这里lightObject是C#中Injection类通过name来访问GameObject
	** 简单理解成Unity中组件挂载的GameObject,灯光
	print("injected object", lightObject)
	lightCpnt= lightObject:GetComponent(typeof(CS.UnityEngine.Light))
end
function update()
	local r = CS.UnityEngine.Vector3.up * CS.UnityEngine.Time.deltaTime * speed
	** self表示LuaBehaviour.cs中的this,也就是挂载脚本那个对象Cube
	self.transform:Rotate(r)
	lightCpnt.color = CS.UnityEngine.Color(CS.UnityEngine.Mathf.Sin(CS.UnityEngine.Time.time) / 2 + 0.5, 0, 0, 1)
end
function ondestroy()
    print("lua destroy")
end

Unity中的情况

三 UI绑定与交互

C# 同上LuaBehaviour.cs文件
Lua文件 ButtonInteraction.lua

function start()
	print("lua start...")
	** 这里的self就是LuaBehaviour组件本身this
	** 获得Button组件,对onClick注册监听方法
	** input是注入器绑定的对象,即InputField对象
	** 这里功能是对按钮注册一个匿名函数,当点击按钮时候,回调匿名函数
	** 匿名函数是输出输入框中的文本
	self:GetComponent("Button").onClick:AddListener(function()
		print("clicked, you input is '" ..input:GetComponent("InputField").text .."'")
	end)
end

Unity中的情况

四 通过元表,实现lua面向对象

C# InvokeLua.cs

namespace XLuaTest
{
	//EventArgs是自定义事件类
	//PropertyChangedEventArgs用于做属性改变事件
    public class PropertyChangedEventArgs : EventArgs
    {
        public string name;
        public object value;
    }
    public class InvokeLua : MonoBehaviour
    {
        [CSharpCallLua]
        //定义一个接口,里面声明PropertyChangedEventArgs事件
        public interface ICalc
        {
        	//定义一个PropertyChangedEventArgs类型的事件
            event EventHandler<PropertyChangedEventArgs> PropertyChanged;
            int Add(int a, int b);
            int Mult { get; set; }
            object this[int index] { get; set; }
        }
        [CSharpCallLua]
        //定义一个接口类型的委托CalcNew
        public delegate ICalc CalcNew(int mult, params string[] args);
        //字符串---实际上是lua代码
        private string script = @"
        		*局部 表calc_mt  实际是下面构建一个表A的元表M
        		* 元表M的元方法__index是一个表I
        		* 用于模拟面向对象的
        		* 当我们构建的表A这种寻找一个变量(方法)时候
        		* (1)首先去表找,找的到则返回,若找不到继续下一步
        		* (2)判断表是否有元表,若没有返回nil,若有继续下一步
        		* (3)判断元表中是否有元方法__index,若元方法为nil,则返回nil
        		*      若元方法存在,则判断元方法__index是函数还是一个表
        		*      若元方法是一个函数,则返回函数值
        		* 	   若元方法是一个表,则将该表作为目标重复(1)(2)(3)
        		* 提示,这里将元表M的元方法__index设为一个表,表里面有许多方法,例如Add
                local calc_mt = {
                    __index = {
                        Add = function(self, a, b)
                            return (a + b) * self.Mult
                        end,
                        get_Item = function(self, index)
                            return self.list[index + 1]
                        end,
                        set_Item = function(self, index, value)
                            self.list[index + 1] = value
                            self:notify({name = index, value = value})
                        end,
                        add_PropertyChanged = function(self, delegate)
	                        if self.notifylist == nil then
		                        self.notifylist = {}
	                        end
	                        table.insert(self.notifylist, delegate)
                            print('add',delegate)
                        end,                    
                        remove_PropertyChanged = function(self, delegate)
                            for i=1, #self.notifylist do
		                        if CS.System.Object.Equals(self.notifylist[i], delegate) then
			                        table.remove(self.notifylist, i)
			                        break
		                        end
	                        end
                            print('remove', delegate)
                        end,
                        notify = function(self, evt)
	                        if self.notifylist ~= nil then
		                        for i=1, #self.notifylist do
			                        self.notifylist[i](self, evt)
		                        end
	                        end	
                        end,
                    }
                }
                * 新建一个表Calc,相关于类,继承与calc_mt
                * 定义一个全局表,增加一个叫做New的函数
                * New函数返回一个元表,将calc_mt设置为{}表的元表
                * {}中函数将mult赋值给Mult,带一个list表
                Calc = {
                	* New可以理解成构造函数
	                New = function (mult, ...)
                        print(...)
                        return setmetatable({Mult = mult, list = {'aaaa','bbbb','cccc'}}, calc_mt)
                        * 等同于一下写法
                        * local a = {Mult = mult, list = {'aaaa','bbbb','cccc'}}
                        * local b = setmetatable(a, calc_mt)
                        * return b
                    end
                }
	        ";
        // Use this for initialization
        void Start()
        {
            LuaEnv luaenv = new LuaEnv();
            Test(luaenv);//调用了带可变参数的delegate,函数结束都不会释放delegate,即使置空并调用GC
            luaenv.Dispose();
        }

        void Test(LuaEnv luaenv)
        {
        	//读取lua代码
            luaenv.DoString(script);
            //luaenv.Global.GetInPath用于获取Lua中的方法
            //获得CalcNew的构造函数的引用,并映射到CalcNew委托上
            CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>("Calc.New");
            //创建一个Calc的lua对象,并映射到CS上ICalc接口
            //calc_new(10, "hi", "john")等价于Calc.New(10, "hi", "john")
            //Mult = mult = 10, ... == "hi", "john"
            ICalc calc = calc_new(10, "hi", "john"); //constructor
            //调用lua元表的表I中Add方法
            //输出 (1+2)*10 = 30
            Debug.Log("sum(*10) =" + calc.Add(1, 2));
            calc.Mult = 100;
            //输出 (1+2)*100 = 30
            Debug.Log("sum(*100)=" + calc.Add(1, 2));
            //索引 *** 作会用到get_Item和set_Item
            //在lua中索引是从1开始
            //在C#中索引是从0开始,这里是C#
            Debug.Log("list[0]=" + calc[0]);
            Debug.Log("list[1]=" + calc[1]);
			//委托绑定方法Notify
            calc.PropertyChanged += Notify;
            calc[1] = "dddd";
            Debug.Log("list[1]=" + calc[1]);

            calc.PropertyChanged -= Notify;

            calc[1] = "eeee";
            Debug.Log("list[1]=" + calc[1]);
        }

        void Notify(object sender, PropertyChangedEventArgs e)
        {
            Debug.Log(string.Format("{0} has property changed {1}={2}", sender, e.name, e.value));
        }

        // Update is called once per frame
        void Update()
        {

        }
    }
五 NoGC Lua访问C#函数无gc

C# NoGc.cs

[LuaCallCSharp] lua调用C#
[CSharpCallLua] C#调用lua
[GCOptimize] C#纯值类型

namespace XLuaTest
{
    [GCOptimize]
    [LuaCallCSharp]
    public struct Pedding
    {
        public byte c;
    }

    [GCOptimize]
    [LuaCallCSharp]
    public struct MyStruct
    {
        public MyStruct(int p1, int p2)
        {
            a = p1;
            b = p2;
            c = p2;
            e.c = (byte)p1;
        }
        public int a;
        public int b;
        public decimal c;
        public Pedding e;
    }

    [LuaCallCSharp]
    public enum MyEnum
    {
        E1,
        E2
    }

    [CSharpCallLua]
    public delegate int IntParam(int p);

    [CSharpCallLua]
    public delegate Vector3 Vector3Param(Vector3 p);

    [CSharpCallLua]
    public delegate MyStruct CustomValueTypeParam(MyStruct p);

    [CSharpCallLua]
    public delegate MyEnum EnumParam(MyEnum p);

    [CSharpCallLua]
    public delegate decimal DecimalParam(decimal p);

    [CSharpCallLua]
    public delegate void ArrayAccess(Array arr);

    [CSharpCallLua]
    public interface IExchanger
    {
        void exchange(Array arr);
    }

    [LuaCallCSharp]
    public class NoGc : MonoBehaviour
    {
        LuaEnv luaenv = new LuaEnv();

        IntParam f1;
        Vector3Param f2;
        CustomValueTypeParam f3;
        EnumParam f4;
        DecimalParam f5;

        ArrayAccess farr;
        Action flua;
        IExchanger ie;
        LuaFunction add;

        [NonSerialized]
        public double[] a1 = new double[] { 1, 2 };
        [NonSerialized]
        public Vector3[] a2 = new Vector3[] { new Vector3(1, 2, 3), new Vector3(4, 5, 6) };
        [NonSerialized]
        public MyStruct[] a3 = new MyStruct[] { new MyStruct(1, 2), new MyStruct(3, 4) };
        [NonSerialized]
        public MyEnum[] a4 = new MyEnum[] { MyEnum.E1, MyEnum.E2 };
        [NonSerialized]
        public decimal[] a5 = new decimal[] { 1.00001M, 2.00002M };

        public float FloatParamMethod(float p)
        {
            return p;
        }

        public Vector3 Vector3ParamMethod(Vector3 p)
        {
            return p;
        }

        public MyStruct StructParamMethod(MyStruct p)
        {
            return p;
        }

        public MyEnum EnumParamMethod(MyEnum p)
        {
            return p;
        }

        public decimal DecimalParamMethod(decimal p)
        {
            return p;
        }

        // Use this for initialization
        void Start()
        {
            luaenv.DoString(@"
                function id(...)
                    return ...
                end

                function add(a, b) return a + b end
            
                function array_exchange(arr)
                    arr[0], arr[1] = arr[1], arr[0]
                end

                local v3 = CS.UnityEngine.Vector3(7, 8, 9)
                local vt = CS.XLuaTest.MyStruct(5, 6)

                function lua_access_csharp()
                    monoBehaviour:FloatParamMethod(123) --primitive
                    monoBehaviour:Vector3ParamMethod(v3) --vector3
                    local rnd = math.random(1, 100)
                    local r = monoBehaviour:Vector3ParamMethod({x = 1, y = 2, z = rnd}) --vector3
                    assert(r.x == 1 and r.y == 2 and r.z == rnd)
                    monoBehaviour:StructParamMethod(vt) --custom struct
                    r = monoBehaviour:StructParamMethod({a = 1, b = rnd, e = {c = rnd}})
                    assert(r.b == rnd and r.e.c == rnd)
                    monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2) --enum
                    monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])
                    monoBehaviour.a1[0], monoBehaviour.a1[1] = monoBehaviour.a1[1], monoBehaviour.a1[0] -- field
                end

                exchanger = {
                    exchange = function(self, arr)
                        array_exchange(arr)
                    end
                }

                A = { B = { C = 789}}
                GDATA = 1234;
            ");

            luaenv.Global.Set("monoBehaviour", this);

            luaenv.Global.Get("id", out f1);
            luaenv.Global.Get("id", out f2);
            luaenv.Global.Get("id", out f3);
            luaenv.Global.Get("id", out f4);
            luaenv.Global.Get("id", out f5);

            luaenv.Global.Get("array_exchange", out farr);
            luaenv.Global.Get("lua_access_csharp", out flua);
            luaenv.Global.Get("exchanger", out ie);
            luaenv.Global.Get("add", out add);

            luaenv.Global.Set("g_int", 123);
            luaenv.Global.Set(123, 456);
            int i;
            luaenv.Global.Get("g_int", out i);
            Debug.Log("g_int:" + i);
            luaenv.Global.Get(123, out i);
            Debug.Log("123:" + i);
        }


        // Update is called once per frame
        void Update()
        {
            // c# call lua function with value type but no gc (using delegate)
            f1(1); // primitive type
            f2(new Vector3(1, 2, 3)); // vector3
            MyStruct mystruct1 = new MyStruct(5, 6);
            f3(mystruct1); // custom complex value type
            f4(MyEnum.E1); //enum
            decimal dec1 = -32132143143100109.00010001010M;
            f5(dec1); //decimal

            // using LuaFunction.Func<T1, T2, TResult>
            add.Func<int, int, int>(34, 56); // LuaFunction.Func<T1, T2, TResult>

            // lua access c# value type array no gc
            farr(a1); //primitive value type array
            farr(a2); //vector3 array
            farr(a3); //custom struct array
            farr(a4); //enum arry
            farr(a5); //decimal arry

            // lua call c# no gc with value type
            flua();

            //c# call lua using interface
            ie.exchange(a2);

            //no gc LuaTable use
            luaenv.Global.Set("g_int", 456);
            int i;
            luaenv.Global.Get("g_int", out i);

            luaenv.Global.Set(123.0001, mystruct1);
            MyStruct mystruct2;
            luaenv.Global.Get(123.0001, out mystruct2);

            decimal dec2 = 0.0000001M;
            luaenv.Global.Set((byte)12, dec1);
            luaenv.Global.Get((byte)12, out dec2);

            int gdata = luaenv.Global.Get<int>("GDATA");
            luaenv.Global.SetInPath("GDATA", gdata + 1);

            int abc = luaenv.Global.GetInPath<int>("A.B.C");
            luaenv.Global.SetInPath("A.B.C", abc + 1);

            luaenv.Tick();
        }

        void OnDestroy()
        {
            f1 =  null;
            f2 = null;
            f3 = null;
            f4 = null;
            f5 = null;
            farr = null;
            flua = null;
            ie = null;
            add = null;
            luaenv.Dispose();
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/607062.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-14
下一篇 2022-04-14

发表评论

登录后才能评论

评论列表(0条)

保存