- 首先学习下LuaEnv类(Lua虚拟机,建议全局唯一)
object[] DoString(string chunk, string chunkName = "chuck", LuaTable env = null) 描述: 执行一个代码块。 参数: chunk: Lua代码; chunkName: 发生error时的debug显示信息中使用,指明某某代码块的某行错误; env :为这个代码块; 返回值: 代码块里return语句的返回值; 比如:return 1, “hello”,DoString返回将包含两个object, 一个是double类型的1, 一个是string类型的“hello” 例子: LuaEnv luaenv = new LuaEnv(); object[] ret = luaenv.DoString("print(‘hello’)\r\nreturn 1") UnityEngine.Debug.Log("ret="+ret[0]); luaenv.Dispose() T LoadString<T>(string chunk, string chunkName = "chunk", LuaTable env = null) 描述: 加载一个代码块,但不执行,只返回类型可以指定为一个delegate或者一个LuaFunction 参数: chunk: Lua代码; chunkName: 发生error时的debug显示信息中使用,指明某某代码块的某行错误; env :为这个代码块; 返回值: 代表该代码块的delegate或者LuaFunction类; LuaTable Global; 描述: 代表lua全局环境的LuaTable void Tick() 描述: 清除Lua的未手动释放的LuaBase(比如,LuaTable, LuaFunction),以及其它一些事情。 需要定期调用,比如在MonoBehaviour的Update中调用。 void AddLoader(CustomLoader loader) 描述: 增加一个自定义loader 参数: loader:就一个回调,其类型为delegate byte[] CustomLoader(ref string filepath),当一个文件被require时,这个loader会被回调,其参数是require的参数,如果该loader找到文件,可以将其读进内存,返回一个byte数组。如果需要支持调试的话,而filepath要设置成IDE能找到的路径(相对或者绝对都可以) void Dispose() 描述: Dispose该LuaEnv。 LuaEnv的使用建议:全局就一个实例,并在Update中调用GC方法,完全不需要时调用Dispose
示例代码: 执行字符串
using UnityEngine;
using XLua;
public class HelloWorld01 : MonoBehaviour {
private LuaEnv luaenv;
// Use this for initialization
void Start () {
luaenv = new LuaEnv();
luaenv.DoString("print('Hello world!')"); //参数是lua程序,注意参数既要符合C#的语法规范(传字符串要加“”),又要符合lua语法规范
luaenv.DoString(" CS.UnityEngine.Debug.Log('Hello world') "); //在Lua代码中调用C#代码,要有CS标识
}
/// <summary>
/// 用完要记得释放
/// </summary>
private void OnDestroy()
{
luaenv.Dispose();
}
}
2.从Lua源文件中读取Lua代码并运行
结构如下图:
首先创建Lua文件夹,并加上一个.txt后缀更改成文本格式,比如helloworld.lua.txt(注意后面的.txt):
print("Hello world from file") a=2 b=3 print(a+b)
读取并运行文件中的Lua代码:
TextAsset ta = Resources.Load<TextAsset>("helloworld.lua"); // 加载 helloworld.lua.txt文本,注意加载.lua文件要加后缀 LuaEnv env = new LuaEnv(); env.DoString(ta.text); env.Dispose();
3.通过内置的Loader加载lua源文件
- 用lua的require函数即可
- require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。目前xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是因为Resource只支持有限的后缀,放Resources下的lua文件得加上txt后缀。
- 建议的加载Lua脚本方式是:整个程序就一个DoString("require 'main'"),然后在main.lua加载其它脚本(类似lua脚本的命令行执行:lua main.lua)。
LuaEnv env = new LuaEnv(); //引入并执行Lua代码,是使用loader来加载helloworld.lua.txt,找到就会执行代码,没找到就会报错 //要确保文件在Resources文件夹下,并保证文件名一致 env.DoString("require 'helloworld'"); env.Dispose();
loader没有找到文件所报的错误:
4.自定义Loader
当lua脚本放在自定义目录下时使用内置loader时找不到的,因此需要自定义loader
- 在xLua加自定义loader是很简单的,只涉及到一个接口:
public delegate byte[] CustomLoader(ref string filepath);
public void LuaEnv.AddLoader(CustomLoader loader)
- 通过AddLoader可以注册个回调,该回调参数是字符串,lua代码里头调用require时,参数将会透传给回调,回调中就可以根据这个参数去加载指定文件,如果需要支持调试,需要把filepath修改为真实路径传出。该回调返回值是一个byte数组,如果为空表示该loader找不到,否则则为lua文件的内容。
- 有了这个就简单了,用IIPS的IFS?没问题。写个loader调用IIPS的接口读文件内容即可。文件已经加密?没问题,自己写loader读取文件解密后返回即可
using UnityEngine; using XLua; using System.IO; public class CreateLoader : MonoBehaviour { void Start () { LuaEnv env = new LuaEnv(); env.AddLoader(MyLoader);//参数是委托的方法名,其实是自定义方法 //require时会将名字传递给每个loader查找,先执行我们自定义的loader,如果自定义loader返回不为空,则执行改代码,不会再执行内置的loader env.DoString("require 'test007'"); env.Dispose(); } private byte[] MyLoader(ref string filePath) { string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt"; return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath)); } }