Lua

Xlua摘要

Posted by 蔡华的博客 on October 5, 2017

加载机制

  • xlua在加载lua文件时会使用多个loader,LuaEnv的构造函数中有这么一段代码:
AddSearcher(StaticLuaCallbacks.LoadBuiltinLib, 2); // just after the preload searcher
AddSearcher(StaticLuaCallbacks.LoadFromCustomLoaders, 3);
#if !XLUA_GENERAL
AddSearcher(StaticLuaCallbacks.LoadFromResource, 4);
AddSearcher(StaticLuaCallbacks.LoadFromStreamingAssetsPath, -1);
#endif
  • 从这段代码可以看出xlua主要的4个加载器分别是内置的lua的LoadBuiltinLib,已经lua可能存在的两个目录,一个是Resources、另一个是StreamingAssets,通常来说我们也很有可能会把lua代码放到这两个里面。尤其是当用lua做热更新的时候,StreamingAssets是一个很好的选择。
  • 当LuaEnv遇到一个require的时候,就开始从这四个文件夹找

lua调用C#代码

  • unity中C#类分为两种,一种是继承了MonoBehaviour的,一种是一般的C#类。这两种都可以在lua中调用,但是调用方式不同。但是都需要给LuaCallCSharp这个attribute。

对于一般的C#类型,可以使用这样的方式

local testClass = CS.Test
local test = testClass()
test.foo()
  • 对于继承MonoBehaviour的类是不能用上述方法的,因为在实例化的时候会报错。xlua在生wrap的时候没有考虑是否继承自mono,继承自mono的类不能用new,所以会报错。只能用下面的方法,注意第一个是已经在某个游戏对象上挂了脚本的情况,第二个是用lua动态添加脚本。
self:GetComponent("MainUI"):LoadScene("class1/class1")	

-- 或者

local mainui = self.gameObject:AddComponent(typeof(CS.MainUI))
mainui:LoadScene("class1/class1")
  • 需要注意一下对于静态方法是用.,非静态是用:,其实也可以用.但是需要在函数定义的时候带自己self参数。对于unity中的一些函数这里尤为重要,比如
-- 因为Find是静态方法所以用.
local cubes = GameObject.Find("Cubes")
-- 而Transform.Find其实是依赖于一个具体的GameObject的所以要用:
cube1 = cubes.transform:Find("Cube1").gameObject

lua与C#代码结合

  • 如果想使用xlua的LuaBehaviour这个脚本,需要注意的是不能用加载器加载lua代码,而是dostring,否则不能使用self、注入的对象。但是awake方法是可以用的。需要注意要使用GetInPath,get方法我没成功过。
 // 用对象名字作为加载脚本的查询名字
 string luaname = GameRoot.Instance.GlobleUtil.NameDeleteClone(gameObject.name);

 // 直接用byte[] dostring
 AssetBundle bundle = AssetBundle.LoadFromFile("Assets/StreamingAssets/main/lua");
 TextAsset lua = bundle.LoadAsset("MainUI.lua", typeof(TextAsset)) as TextAsset;
 luaEnv.DoString(lua.bytes, luaname, scriptEnv);

 // 用 custom loader加载 但是无法使用self,也无法获取luaAwake这类的方法
 //luaEnv.DoString("require  '" + luaname + "'", luaname, scriptEnv);

 Action luaAwake = scriptEnv.GetInPath<Action>("MainUI.awake");
 luaStart = scriptEnv.GetInPath<Action>("MainUI.start");
 luaUpdate = scriptEnv.GetInPath<Action>("MainUI.update");
 luaOnDestroy = scriptEnv.GetInPath<Action>("MainUI.ondestroy");

关于ref和out修饰符

  • 一开始我测试的时候是本以为lua调用ref传入的参数,也会返回出修改的结果,但出乎我的意料,并没能修改,经过作者提示,lua是通过返回值返回的ref参数,如果函数本身就有返回值,那么最后一个参数是返回的ref或者out参数,如果是一个没有返回值的函数(C#中),在lua中同样可以让它给变量赋值,赋的值就是ref的结果。