(一)先下载xlua的源码
地址:https://github.com/Tencent/xLua
下载好了源码之后把源码中的两个文件夹导入工程
(二)hello world
注意:lua虚拟机对象建议全局只有一个。
using UnityEngine;
using XLua;//使用这个要框架一定要引入命名空间
public class HelloWorld : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();//xlua是在虚拟机上运行的,所以要有虚拟机对象
luaEnv.DoString("print('my first xlua print hello world')");//利用dostring执行lua代码
}
// Update is called once per frame
void Update()
{
}
}
(三)读取和执行lua文件
三种方式:第一种以文本资源方式读取
新建lua脚本,扩展名如图所示
该脚本里面就一句输出语句
然后我们在c#脚本里用文本资源读取的方式执行该文件,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaFileDemo : MonoBehaviour
{
public TextAsset luaTextAsset;
// Start is called before the first frame update
void Start()
{
string luastring = luaTextAsset.text;//读取文本里的lua语句
LuaEnv luaEnv = new LuaEnv();//lua虚拟机环境
luaEnv.DoString(luastring);//执行txt文件里的lua语句
}
// Update is called once per frame
void Update()
{
}
}
第二种方式;用require直接引用文件名,这种方式是系统自带的加载器方式
首先引用的lua文件要在Resources文件夹下,不然找不到,这里是放到了resources的子文件夹下(不过不建议这么做,因为如果后面加txt扩展名的时候,即使用全路径也会报错找不到,而且用.lua.txt的扩展名也能让人很方便的看出这就是lua文件)
代码如下
这里的lua是:luaFile.lua
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaFileDemo : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
//ps:如果这里用luafile找不到文件的话,就使用全路径,从assets下开始的那种
//luaFile是lua文件的名字,这里可以直接用lua扩展名,而不需要lua.txt
luaEnv.DoString("require'Assets/Resources/luaFileDemo/luaFile'");
//这种方式是系统的加载器自带的加载方式
}
}
第三种,自定义加载器
这里用的lua文件是直接放在resources文件夹下的, 且文件是luaFile.lua.txt
第三种自定义加载器更商业化的做法
public class CustomerLoader : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
//里面是自定义加载器
luaEnv.AddLoader(MyCustomLoader);
//如果有自定义加载器,就先去找自定义加载器,然后再执行lua语句,没有自定义加载器,就用系统默认的
//吐槽:也是奇怪了,带luaFile.lua.txt,只能直接放到resources下,不能放到resources的文件夹下,不然怎么样都识别不到?
luaEnv.DoString("require 'luaFile'");
}
public byte[] MyCustomLoader(ref string filepath)
{
Debug.Log(filepath);//注意这里打印出来的是luaFile,文件路径,源码里string定义的也是filepath
//来做个判断,如果找的到这个文件路径就返回文件的byte[],没有就返回空的字符串转化成的byte[]
//这样的好处是即使没有这个文件也不会报错
//因为resources不支持多个扩展名,所以要加上.lua
string path = filepath + ".lua";
TextAsset textAsset = Resources.Load(path) as TextAsset;
if (textAsset == null)
{
//注意,这里要写成lua语句,直接写中文,是读不成lua语句的
return System.Text.Encoding.UTF8.GetBytes("print('文件未找到')");
}
else
{
return System.Text.Encoding.UTF8.GetBytes(textAsset.text);
}
}
}
(四)如何用c#调用lua文件里的内容,如变量
代码如下
注意:如果再c#代码中修改了nu1的值,是不会影响到lua文件里的num1的值的
public class CCallLuaVarDemo : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.DoString("require'luaFile'");
//从加载的lua脚本中读取num1的值
int nu1 = luaEnv.Global.Get<int>("num1");
print(nu1);
}
}
(五)在c#中修改lua文件里的内容,如变量
代码如下
public class CCallLuaVarDemo : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.DoString("require'luaFile'");
//从加载的lua脚本中读取num1的值
int nu1 = luaEnv.Global.Get<int>("num1");//这里nu1的值还是10
//修改lua文件里num1的值
luaEnv.Global.Set<string, int>("num1", 1);
//输出修改后lua文件里的变量num1的值
luaEnv.DoString("print('num1')");
}
}
注意,如果有过个虚拟机都对lua文件里的num1操作,输出的值是相互独立,互不影响的。所以建立全局只有一个lua虚拟机对象。
(六)c#中的类与lua文件中table的映射
可以参考这篇文章:关于表的映射
lua脚本里这样写
print("Hello This is a lua file")
--lua文件里建立的各种类型不同的变量
num1=10
str1="this is lua string "
table1={
name="root",
age=1,
13,
f=function()
print("this is lua function")
end,
"red","blue","yellow",
}
c#映射表中键值对的代码:
public class CSCallLuaTable : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.DoString("require 'luaFile'");
//操作表中的键值对
//输出lua文件中表table中的name:“root”,age:1
//这里是lua文件中的的table1表映射到TableTemp类对象上
TableTemp t = luaEnv.Global.Get<TableTemp>("table1");
Debug.Log(t.name);
Debug.Log(t.age);
//注意这里即使把t.name赋值成了其它的值,也不会影响到table1里本身的name的值 ,即是深拷贝
}
}
//新建一个类来专门映射lua文件中的表
public class TableTemp
{
//用来映射lua文件中表table1中的name:“root”,age:1
//注意这里都要是public不然不好在别的类使用
//这里的变量名都要和表中一一对应
public string name;
public string age;
}
(七)利用c#中的接口使用table中的函数
科普一下:lua中self,点号,冒号的关系
游戏开发unity xlua框架知识系列:This type must add to CSharpCallLua报错解决方式
lua中的代码
print("Hello This is a lua file")
--lua文件里建立的各种类型不同的变量
num1=10
str1="this is lua string "
table1={
name="root",
age=1,
13,
f=function()
print("this is lua function")
end,
"red","blue","yellow",
}
function table1.fun1(self)
print(self.age,self.name)
end
function table1:fun3(num1,num3)
print(self.age,self.name)
print(num1+num3)
end
c#中的代码
using UnityEngine;
using XLua;
public class CSCallLuaTableFunciton : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.DoString("require 'luaFile'");
TableTemp t = luaEnv.Global.Get<TableTemp>("table1");
t.fun1();
t.f();
t.fun3(1, 3);
t.name = "ncount";//注意这里在c#中更改了lua中的name,和之前不一样是浅拷贝。
luaEnv.DoString("print(table1.name)");//但是打开文件似乎还是root?
print(t.name);//这里打印出来也是ncount
}
//用c#中的接口对应lua中的table
//c#调用lua中的table要加下面这个标记
[CSharpCallLua]
public interface TableTemp
{
//接口中没有字段,所以用属性
string name { set; get; }
string age { set; get; }
//对应函数中的三个方法
void f();
void fun1();
void fun3(int x,int y);
}
(八)Dictionary,list与table的映射
dictionary适合表中的键值对,包括函数
list适合没有键的
c#代码如下
public class CSCallLuaTableByDictionary : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.DoString("require 'luaFile'");
//字典适合有键值对的表中对应
Dictionary<string, object> dict1 = new Dictionary<string, object>();
dict1 = luaEnv.Global.Get<Dictionary<string, object>>("table1");
foreach(string key in dict1.Keys)
{
print(key + "," + dict1[key]);
//这里打印的是table中的有键值对的内容,包括函数
//具体打印的是:fun3,function :10 f function :12 name,root 这种类型的
}
//list适合没有键的表中对应
//这里一个容易犯的的错误是,object是小写的,不是大写的
List<object> list1 = new List<object>();
list1 = luaEnv.Global.Get<List<object>>("table1");
foreach(object o in list1)
{
Debug.Log(o.ToString());
}
}