• Unity3D学习笔记(三十一):Xlua(1)


    Xlua:腾讯研发,开源免费
     
    配置:文件解压,拷贝到Unity项目里
    注意:Xlua文件夹不许移动,不许重命名
     
    运行Xlua:
    1、引用命名空间
    2、创建虚拟机
    3、运行lua语句
    4、不需要时,释放虚拟机(LuaEnv:Lua的虚拟机)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;//1、引用Xlua的命名空间
    public class HelloWorld : MonoBehaviour
    {
        //lua的语句
        private string lua = @"print('Hello World') return 1, 'nihao', true";
        //2、创建一个运行lua语句的lua虚拟机
        private LuaEnv luaEnv = new LuaEnv();
    
        void Start()
        {
            //4、运行lua的语句
            //这个方法的参数就是lua的语句,返回值就是运行lua,lua里的最终的返回内容
            object[] obj_arr = luaEnv.DoString(lua);
            foreach (var item in obj_arr)
            {
                Debug.Log(item);
            }
        }
    
    
        private void OnDestroy()
        {
            //3、不需要虚拟机的时候,需要把虚拟机释放掉
            luaEnv.Dispose();
        }
    }
     
    C#调用Lua的文件:
    1、Lua文件的后缀必须是.lua.txt的,file.lua.txt
    2、Lua文件必须放在Resources文件夹下,不可以是子文件夹,默认加载器的原因
    3、Lua文件的默认编码格式必须是UTF-8的。
    4、使用Lua的关键字require调用,不需要写文件后缀,只需要写文件名
    ----例如:file.lua.txt; require 'file'
    5、对于文件的返回值,需要写成 return require 'file'才能获得

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class LuaByFile : MonoBehaviour
    {
        private string lua = @"require 'LuaByFile'";
      //private string lua = @"a = require 'LuaByFile' retrun a";
    
        //private string lua = @"retrun require 'LuaByFile'";
        private LuaEnv luaEnv = new LuaEnv();
    
        void Start()
        {
            object[] obj_arr = luaEnv.DoString(lua);
        }
    
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }
     
    自定义的加载器:能执行我们想要执行的指定文件夹下的Lua文件
    自定义的加载器的参数:require传入的文件名
    自定义的加载器的返回值:要执行的Luad的语句转换成的字节数组(UTF-8转换),如果返回null。证明未找到文件。
    一个lua虚拟机能添加无数个自定义加载器,从第一个加载器中开始找,如果找到了(未返回null),那么就不执行之后的其他的加载器,如果所有的自定义的加载器都未找到,执行默认的加载器,从Resources文件夹中寻找文件,如果默认的也未找到,直接报错。
     
    .lua.txt文件打成AB包
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    using System.IO;
    using System.Text;
    public class CustomeLoader : MonoBehaviour {
    
    
        private LuaEnv luaEnv = new LuaEnv();
        //该文件不在Resources下,默认加载器加载不到
        private string lua = @"require 'CustomeLoader2'";
    
        void Start () {
            //添加一个自定义的加载器
            luaEnv.AddLoader(CustomeLoader1);
            luaEnv.AddLoader(CustomeLoader2);
            luaEnv.DoString(lua);
        }
    
    
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    
    
        /// <summary>
        /// 自定义的加载器
        /// </summary>
        /// <param name="filePath">参数是require后的那个文件名字</param>
        /// <returns></returns>
        /// 返回值就是要执行的lua的转换之后的字节数组,如果返回值是null证明我们未找到该lua文件
        byte[] CustomeLoader1(ref string filePath)
        {
            //filePath:参数是require后的那个文件名字
            //byte[] bytes = System.Text.Encoding.UTF8.GetBytes("print('hello world')");
            //文件所在的绝对路径
            string path = Application.streamingAssetsPath + "/Lua/" + filePath + ".lua.txt";
            if (!File.Exists(path))
            {
                return null;//如果不存在该文件,直接返回null
            }
            StreamReader sr = new StreamReader(path, System.Text.Encoding.UTF8);
            string lua = "";
            try
            {
                lua = sr.ReadToEnd();
            }
            catch (System.Exception)
            {
                throw;
            }
            sr.Close();
            if (lua == "")//如果读取内容为空串,那么返回null,证明未找到该文件
            {        
                return null;
            }
            else
            {
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(lua);
                return bytes;
            }
        }
    
    
        /// <summary>
        /// 从ab包中加载lua文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        byte[] CustomeLoader2(ref string filePath)
        {
            //加载AB包
            AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AB/lua");
            //从ab包中加载所需要的lua文件
            TextAsset lua = ab.LoadAsset<TextAsset>(filePath + ".lua");
            if (lua != null)
            {
                return lua.bytes;
            }
            return null;
        }
    }
     
    C#访问Lua文件里的变量和方法:
     
    C#访问Lua的全局变量
    虚拟机执行一个lua语句之后,lua里的全局的变量或方法,
    都存放在luaEnv.Global中,从Global中获取这些全的变量或方法。
     
    CSharpCallLuaVariate.lua.txt
    print('开始执行Variate.lua')
    a = 1
    b = 1.2
    c = true
    d = '小明'
    print('开始执行Variate.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class CSharpCallLuaVariate : MonoBehaviour {
    
    
        private LuaEnv luaEnv = new LuaEnv();
    
        void Start () {
            luaEnv.DoString("require 'CSharpCallLuaVariate'");
            //虚拟机执行一个lua语句之后,lua里的全局的变量或方法
            //都存放在luaEnv.Global中,从Global中获取这些全的变量或方法
            //泛型是要接收的变量类型,参数是lua里的变量名字
            //返回值就是变量的值
            //int
            int a = luaEnv.Global.Get<int>("a");
            Debug.Log("a: " + a);
            //float
            float b = luaEnv.Global.Get<float>("b");
            Debug.Log("b: " + b);
            //bool
            bool c = luaEnv.Global.Get<bool>("c");
            Debug.Log("c: " + c);
            //string
            string d = luaEnv.Global.Get<string>("d");
            Debug.Log("d: " + d);
        }
           
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }
     
    C#访问全局的table
    1、映射到类或结构体中(值拷贝过程)
    只能把table中的键值对映射到类中的公共变量,并且变量名与键名一致。
    对于类中如果变量多于table的键值对,table键值对多余类中变量,都没有任何的影响
     
    2、使用接口映射
    不光能映射基本类型,还能映射table中的方法。
    Table中的键与接口中的属性名或方法名对应上。
     
    3、使用字典或list映射
    List映射:只能映射索引的数字且连续的,并且只能映射值与list指定了类型一致的元素。
    字典映射:当指定了字典的键类型和值类型之后,table中键与字典的键的类型一致,且键对应的值的类型与字典中值类型一致的也会映射过来。
     
    4、使用XLua提供的LuaTable来映射
     
    CSharpCallLuaTable.lua.txt
    print('开始执行CSharpCallLuaTable.lua')
    t1 = {1, 2, 5, "小明", "nihao"}
    t1.f1 = "name"
    t1.f2 = true
    t1.id = 1
    t1[6] = 6
    t1[9] = 9
    t1.func1 = function()
        print("func1")
    end
    print('开始执行CSharpCallLuaTable.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class CSharpCallLuaTable : MonoBehaviour {
    
    
        private LuaEnv luaEnv = new LuaEnv();
    
    
        void Start()
        {
            luaEnv.DoString("require 'CSharpCallLuaTable'");
    
    
            //1、使用class或struct去映射table(值拷贝过程)
            T1 t1 = luaEnv.Global.Get<T1>("t1");
            t1.Print();
    
    
            //2、可以使用接口去映射(引用拷贝过程)
            IT1 it1 = luaEnv.Global.Get<IT1>("t1");
            Debug.Log("it1:f1: " + it1.f1 + ",f2: " + it1.f2 + ",id: " + it1.id);
            it1.func1();
    
    
            //3、映射到字典或List中(值拷贝过程)
            List<object> list = luaEnv.Global.Get<List<object>>("t1");
            foreach (var item in list)
            {
                Debug.Log("list: " + item);
            }
            Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string, object>>("t1");
            foreach (KeyValuePair<string, object> item in dic)
            {
                Debug.Log("键: " + item.Key + "值: " + item.Value);
            }
    
    
            //4、使用XLua提供的LuaTable来映射
            LuaTable lt = luaEnv.Global.Get<LuaTable>("t1");
            //对于table中字符串作为键的键值对
            string f1 = lt.Get<string>("f1");
            Debug.Log("f1: " + f1);
            //对于table中的数字类型的索引的键值对,在取的时候需要指定键的类型和值的类型
            string a = lt.Get<int, string>(4);
            Debug.Log("第四个索引: " + a);
        }
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
        public class T1
        {
            public string f1;
            public bool f2;
            public int id;
            public void Print()
            {
                Debug.Log("f1: " + f1 + ",f2: " + f2 + ",id: " + id);
            }
        }
        [CSharpCallLua]//需要添加此特性
        public interface IT1//接口里不能有变量,可以用变量
        {
            string f1 { get; set; }
            bool f2 { get; set; }
            int id { get; set; }
            void func1();
        }
    }
     
    C#映射全局的方法
    1、使用委托映射
    Lua中多返回值的情况:如果C#的委托有返回值,那么lua的函数的第一个返回值就是委托的返回值,第二个返回值之后依次对应委托里的out或ref参数传出。
    如果C#的委托是无返回值的,那么lua函数从第一个返回值开始,依次对应委托的out或ref参数传出。
    2、使用LuaFunction映射
     
    CSharpCallLuaFunction.lua.txt
    print('开始执行CSharpCallLuaFunction.lua')
    
    --无参无返回值
    func1 = function()
        print("无参无返回值:func1")
    end
    
    --有参无返回值
    func2 = function(a, b)
        print("有参无返回值:func2:", a, b)
    end
    
    --无参有返回值
    func3 = function()
        print("无参有返回值:func3")
        return 1
    end
    
    --有参有返回值
    func4 = function(a, b)
        print("有参有返回值:func4:", a, b)
        return true
    end
    
    --无参多返回值
    func5 = function()
        print("无参多返回值:func5:")
        return true, false, 1, "小明"
    end
    
    --有参多返回值
    func6 = function(a, b)
        print("有参多返回值:func6:", a, b)
        return true, false, 1, "小明"
    end
    
    print('开始执行CSharpCallLuaFunction.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class CSharpCallLuaFunction : MonoBehaviour {
        private LuaEnv luaEnv = new LuaEnv();
        //映射无参无返回值
        [CSharpCallLua]//加特性自动适配,不用再去做映射,效率高
        private delegate void Func1();
        //映射有参无返回值  参数可以是任意类型
        [CSharpCallLua]
        private delegate void Func2(string a, int b);
        //无参有返回值   最好委托返回值类型与lua中方法的返回值相对应
        [CSharpCallLua]
        private delegate int Func3();
        [CSharpCallLua]
        private delegate void Func4();
        //无参多返回值
        [CSharpCallLua]
        private delegate bool Func5(out bool outOne, ref int outTwo, out string outThree);
        //有参多返回值
        [CSharpCallLua]
        private delegate bool Func6(int a, out bool outOne, int b);
        // Use this for initialization
        void Start () {
            luaEnv.DoString("require'CSharpCallLuaFunction'");
            //全局的方法依旧存储在 Global中
            //1. 全局方法映射到委托
            Func1 func1 = luaEnv.Global.Get<Func1>("func1");
            func1();
            // 对于Lua中任意的方法,C#任意的一个委托类型都能映射过来,
            // 只是对于返回值和参数的情况会忽略处理
            // 最好使用相对应的委托去映射
            //Del func2 = luaenv.Global.Get<Del>("func6");
            // func2();
            Func2 func2 = luaEnv.Global.Get<Func2>("func2");
            func2("小明", 81);
            Func3 func3 = luaEnv.Global.Get<Func3>("func3");
            Debug.Log("func3的返回值" + func3());
            Func5 func5 = luaEnv.Global.Get<Func5>("func5");
            bool outOne = false;
            int outTwo = 0;
            string outThree ="";
            bool rt = func5(out outOne, ref outTwo, out outThree);
            Debug.Log("func5:第1个返回值:" + rt + "第2个返回值:" + outOne + "第3个返回值:" + outTwo + "第4个返回值:" + outThree);
            Func6 func6 = luaEnv.Global.Get<Func6>("func6");
            bool out1;
            bool rt1 = func6(3, out out1, 4);
            Debug.Log(rt1 + "------" + out1);
    
    
            //2. LuaFunction映射,效率低
            LuaFunction luaFunc6 = luaEnv.Global.Get<LuaFunction>("func6");
            //调用方法  参数就是方法的参数,返回值就是lua方法的返回值,多返回值存入数组中
            object[] obj_Arr = luaFunc6.Call(1, 2);
            foreach (var item in obj_Arr)
            {
                Debug.Log(item);
            }
        }
           
           // Update is called once per frame
           void Update () {
                  
           }
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }
     
    Lua调用C#的变量或方法
    调用静态的变量:CS.命名空间.类名.变量或属性名 或  CS.类名.变量或属性名
    调用成员的变量:
    1、类实例化:变量名 = CS.命名空间.类名() 或 CS.类名()
    2、调用成员变量或属性:对象名.变量名或属性名
     
    Lua调用C#的方法
    静态:调用C#的静态方法: CS.命名空间.类名.方法名() 或 CS.类名.方法名()
    非静态的: 调用C#的成员方法: 对象名:方法名()
     
    NewGameObject.lua.txt
    print('开始执行NewGameObject.lua')
    --C#:GameObject obj = new UnityEngine.GameObject();
    --实例化一个对象
    obj = CS.UnityEngine.GameObject();
    print('结束执行NewGameObject.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class NewGameObject : MonoBehaviour {
    
    
        private LuaEnv luaEnv = new LuaEnv();
    
    
        void Start () {
            luaEnv.DoString("require 'NewGameObject' ");
            //GameObject obj = new UnityEngine.GameObject();
        }
    
    
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }

    LuaCallCSharpVariate.lua.txt

    print('开始执行LuaCallCSharpVariate.lua')
    --静态变量:CS.命名空间.类名.变量或属性名 或 CS.类名.变量或属性名
    print("A静态变量", CS.Lesson.A.name)
    --调用成员变量,首先需要new出来对象
    a = CS.Lesson.A()
    --调用成员变量:对象名.变量名或属性名
    print("A成员变量", a.id, a.Sex)
    print('结束执行LuaCallCSharpVariate.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class LuaCallCSharpVariate : MonoBehaviour {
    
    
        private LuaEnv luaEnv = new LuaEnv();
    
    
        void Start()
        {
            luaEnv.DoString("require 'LuaCallCSharpVariate' ");     
        }
    
    
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }
    
    
    namespace Lesson
    {
        public class A
        {
            public static string name = "A";
            public int id;
            private bool sex;
            public bool Sex
            {
                get { return sex; }
                set { sex = value; }
            }
            public A() { id = 1; sex = true; }
        }
    }

    LuaCallCSharpFunction.lua.txt

    print('开始执行LuaCallCSharpFunction.lua')
    
    --C# B.StaticFunc()
    
    --调用C#的静态方法:CS.命名空间.类名.方法名() 或 CS.类名.方法名()
    CS.Lesson.B.StaticFunc()
    
    --调用C#的成员方法
    --实例化一个类对象
    b = CS.Lesson.B()
    
    --调用C#的成员方法:对象名:方法名()
    b:UnStaticFunc()
    
    --Xlua支持通过子类的对象去访问父类的方法、属性、变量
    b:Func()
    
    print('结束执行LuaCallCSharpFunction.lua')
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class LuaCallCSharpFunction : MonoBehaviour {
    
        private LuaEnv luaEnv = new LuaEnv();
    
        void Start()
        {
            luaEnv.DoString("require 'LuaCallCSharpFunction' ");
        }
    
        void Update()
        {
        }
        private void OnDestroy()
        {
            luaEnv.Dispose();
        }
    }
    
    namespace Lesson
    {
        public class B : C
        {
            public static void StaticFunc()
            {
                Debug.Log("这是一个静态方法");
            }
            public void UnStaticFunc()
            {
                Debug.Log("这是一个非静态方法");
            }
        }
        public class C
        {
            public void Func()
            {
                Debug.Log("Func");
            }
        }
    }
    案例 - 用Lua实现游戏物体旋转移动
    Move.lua.txt
    print("开始执行Move")
    
    --参数就是Move的类对象
    Set = function(self)
        move = self
    end
    
    Update = function()
        --C# transform.Rotate(Vector3.up*30 * Time.deltaTime);
        print("Update")
    
        move.transform:Rotate(CS.UnityEngine.Vector3.up * 30 * CS.UnityEngine.Time.deltaTime);
    
        v = CS.UnityEngine.Input.GetAxis("Vertical");
        h = CS.UnityEngine.Input.GetAxis("Horizontal");
    
        move.transform:Translate(CS.UnityEngine.Vector3(h,0,v) * CS.UnityEngine.Time.deltaTime);
    
    end
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    public class Move : MonoBehaviour
    {
        private LuaEnv luaenv = new LuaEnv();
    
    
        [CSharpCallLua]
        private delegate void Del();
        [CSharpCallLua]
        private delegate void Set(Move move);
        private Del update;
    
        void Start()
        {
            luaenv.DoString("require 'Move'");
            Set set = luaenv.Global.Get<Set>("Set");
            set(this);//把自己传递到lua中去
            update = luaenv.Global.Get<Del>("Update");
        }
    
        void Update()
        {
            //transform.Rotate(Vector3.up*30 * Time.deltaTime);
            //transform
            /*
            float v = Input.GetAxis("Vertical");
            float h = Input.GetAxis("Horizontal");
            transform.Translate(new Vector3(h,0,v) * Time.deltaTime);
            */
            if (null != update)
            {
                update();
            }
        }
    
    
        private void OnDestroy()
        {
            update = null;
            luaenv.Dispose();
        }
    }
  • 相关阅读:
    angluar 判断后跳转加参数
    angular 返回上一页
    angular 组件跳转组件 并传参数
    angluar 表单提交时候报错
    angular 中获取select选中的值
    javascript
    将数据渲染到页面的方式:模版
    将数据渲染到页面的几种方式
    跨域
    ajax
  • 原文地址:https://www.cnblogs.com/vuciao/p/10363707.html
Copyright © 2020-2023  润新知