前言
xLua是Unity3D下Lua编程解决方案。全平台支持用Lua修复C#代码bug。
XLua顶替Lua的优势
xLua热补丁技术支持在运行时把一个C#实现(函数,操作符,属性,事件,或者整个类)替换成Lua实现,意味着你可以:
1、平时的逻辑使用C#脚本即可。
2、运行也是C#,性能秒杀Lua。
3、有bug的地方下发个Lua脚本fix了,下次整体更新时可以把Lua的实现换回正确的C#实现,更新时甚至可以做到不重启游戏。
最最简单的初步应用
C#使用Lua脚本的方法
-
下载xLua后解压到Unity工程的Asset目录。
-
创建一个MonoBehaviour拖到场景。
-
在Start()函数加入以下代码支持控制台输出“hello world”。
XLua.LuaEnv luaenv = new XLua.LuaEnv(); //Lua的虚拟机一个项目只有一个。
luaenv.DoString( "CS.UnityEngine.Debug.Log('hello world')" );//DoString内的参数时合法的Lua代码即可。
luaenv.Dispose();
C#调用lua系统函数math.max
XLua支持把一个Lua函数绑定到C#delegate。
使用方法如下:
声明一个delegate,并为它加上CSharpCallLua标签:
[XLua.CSharpCallLua]
public delegate double LuaMax( double a, double b);
后续即可通过以下代码进行math.max的调用。
var max = luaenv.Global.GetInPath( "math.max" );
Debug.Log( "max:" + max(32, 12)); //很酷的是这里的函数调用时不产生gc alloc的。
Tip:注意不能在luaenv销毁后进行如此调用
再深入一丢的应用(对象变量的绑定)
首先搞一个C#脚本LuaMgr支持C#变量和Lua的绑定
//指定Lua脚本
public TextAsset luaScript;
public Injection[] injections;
//Lua虚拟机运行的一个上下文对象
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即为this
scriptEnv.Set("self", this);
//注册绑定其他对象
foreach (var injection in injections)
{
scriptEnv.Set(injection.name, injection.value);
}
//执行Lua脚本LuaTestScript代码
luaEnv.DoString(luaScript.text, "LuaTestScript", scriptEnv);
//添加生命周期函数
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();
}
}
以上代码编写后就支持
-
在Lua中使用self即为this
-
给Lua添加Unity3D的生命周期函数
技术实现的优势
支持泛型
除了运行时动态实例化之外都支持泛型。
如果需要运行时动态实例化则需要jit的支持。并且即使如此当前在IOS下也是不可行的,
举个例子
如果你配了对Dictionary生成代码,那这个类型是可以用的,但如果更新的lua代码,想用一个Dictionary,这个类型之前没生成代码,而且C#里头也没任何地方使用过,这就不支持。静态实例化的泛型,其实和非泛型类型处理上没区别。
委托事件的应用
一般方案都有delegate的支持,一般仅用于在lua侧主动传递/设置一个lua函数到C#,xLua支持更为完整,比如:
-
支持C#主动用delegate来引用一个lua函数。用delegate代替类似object[]Call(params object[] args)的接口调用lua最大的好处是可以避免值类型传递时的boxing/unboxing,还有参数数组,返回值数组的gc alloc。
-
支持返回delegate的delegate,可对应到lua的高阶函数;
-
作为这技术的一个延伸,xLua支持用一个c# interface引用一个lua table,这个特性和一些IOC框架配合可以实现C#和Lua间无感知(模块间都通过interface耦合,然后由框架去组装)。
支持生成代码及反射
现有的项目代码有些代码量以及接近苹果的80M Text段的限制,对他们来说,代码量大小关乎到能否发布,虽然反射方式性能不如生成代码,但是它对安装包影响小。因此也不能一味的采用生成代码方案来替代反射的方案。