博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity3D学习笔记(三十一):Xlua(1)
阅读量:5305 次
发布时间:2019-06-14

本文共 13887 字,大约阅读时间需要 46 分钟。

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();    }    ///     /// 自定义的加载器    ///     /// 参数是require后的那个文件名字    /// 
/// 返回值就是要执行的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; } } /// /// 从ab包中加载lua文件 /// /// ///
byte[] CustomeLoader2(ref string filePath) { //加载AB包 AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AB/lua"); //从ab包中加载所需要的lua文件 TextAsset lua = ab.LoadAsset
(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 = 1b = 1.2c = trued = '小明'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
("a"); Debug.Log("a: " + a); //float float b = luaEnv.Global.Get
("b"); Debug.Log("b: " + b); //bool bool c = luaEnv.Global.Get
("c"); Debug.Log("c: " + c); //string string d = luaEnv.Global.Get
("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 = truet1.id = 1t1[6] = 6t1[9] = 9t1.func1 = function() print("func1")endprint('开始执行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.Print(); //2、可以使用接口去映射(引用拷贝过程) IT1 it1 = luaEnv.Global.Get
("t1"); Debug.Log("it1:f1: " + it1.f1 + ",f2: " + it1.f2 + ",id: " + it1.id); it1.func1(); //3、映射到字典或List中(值拷贝过程) List
list = luaEnv.Global.Get
>("t1"); foreach (var item in list) { Debug.Log("list: " + item); } Dictionary
dic = luaEnv.Global.Get
>("t1"); foreach (KeyValuePair
item in dic) { Debug.Log("键: " + item.Key + "值: " + item.Value); } //4、使用XLua提供的LuaTable来映射 LuaTable lt = luaEnv.Global.Get
("t1"); //对于table中字符串作为键的键值对 string f1 = lt.Get
("f1"); Debug.Log("f1: " + f1); //对于table中的数字类型的索引的键值对,在取的时候需要指定键的类型和值的类型 string a = lt.Get
(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 1end--有参有返回值func4 = function(a, b)    print("有参有返回值:func4:", a, b)    return trueend--无参多返回值func5 = function()    print("无参多返回值:func5:")    return true, false, 1, "小明"end--有参多返回值func6 = function(a, b)    print("有参多返回值:func6:", a, b)    return true, false, 1, "小明"endprint('开始执行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(); // 对于Lua中任意的方法,C#任意的一个委托类型都能映射过来, // 只是对于返回值和参数的情况会忽略处理 // 最好使用相对应的委托去映射 //Del func2 = luaenv.Global.Get
("func6"); // func2(); Func2 func2 = luaEnv.Global.Get
("func2"); func2("小明", 81); Func3 func3 = luaEnv.Global.Get
("func3"); Debug.Log("func3的返回值" + func3()); Func5 func5 = luaEnv.Global.Get
("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"); bool out1; bool rt1 = func6(3, out out1, 4); Debug.Log(rt1 + "------" + out1); //2. LuaFunction映射,效率低 LuaFunction luaFunc6 = luaEnv.Global.Get
("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 = selfendUpdate = 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(this);//把自己传递到lua中去 update = luaenv.Global.Get
("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(); }}

 

转载于:https://www.cnblogs.com/cnwuchao/p/10363707.html

你可能感兴趣的文章
Java IO设计模式彻底分析 (转载)
查看>>
用css实现自适应正方形
查看>>
Beta阶段项目总结
查看>>
Remove Duplicates from Sorted Array II
查看>>
Find Peak Element
查看>>
C# MD5一句话加密
查看>>
C#网络编程系列文章之Socket实现异步TCP服务器
查看>>
浅谈按位存储
查看>>
趣图:当客户第一次尝试应用程序时
查看>>
Sqlite(数据库)
查看>>
1070. 结绳(25)
查看>>
js函数节流和函数防抖
查看>>
点击出现闪烁
查看>>
Eclipse+Maven+Spring+CXF 构建webservice 服务
查看>>
聊聊Greenplum的那些事
查看>>
下起了雨
查看>>
Type of 'this' pointer in C++
查看>>
小记sql server临时表与表变量的区别
查看>>
大神校友心得
查看>>
主机管理+堡垒机系统开发:webssh(十)
查看>>