我们通常用继承了monobehaivor的C#脚本来开发游戏,本节我尝试用lua脚本来制作这样这个脚本,在lua侧来开发实现业务逻辑。
1、根据unity对象的生命周期,我们定义常见的几个MonoBehaivor的函数,我们先创建一个lua脚本,包含了这里面的几个通用函数。
LuaMonoBehaviour.lua文件,目录在Assets\LuaScripts\Common下
function Awake()
print("this is Awake function",self.gameObject.name)
end
function OnEnable()
print("this is OnEnable function")
end
function Start()
print("this is Start function")
end
function Update()
print("this is Update function")
end
function OnDestroy()
print("this is OnDestroy function")
end
2、然后我们还要在C#端定义一个XLuaMonoBehaviour.cs类
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class XLuaMonoBehaviour : MonoBehaviour
{
private void Awake(){}
private void OnEnable(){}
void Start() {}
void Update(){}
private void OnDestroy(){}
}
3、我们需要将C#类和lua脚本通过某一种方式建立一种联系,可以说是委托吧(下面讲到)。使得当我们在unity对象上挂在了XLuaMonoBehaviour.cs 类的时候,同样的调用到了LuaMonoBehaviour.lua脚本,并执行了其相对应的方法
4、然后我们需要在C#端定义一些桥接脚本,用来连接彼此之间相对应的方法。(在xlua官方教程中有个写好的LuaBehaviour.cs可以参考,我搬运过来稍微修改了下)
首先我们需要用到上一篇文章(xLua笔记(1)—Lua启动类)的XLuaManager类,添加几个
方法
private void InitLuaEnv()
{
luaEnv = new LuaEnv();
if (luaEnv != null)
{
luaEnv.AddLoader(CustomLoader);
//设置__index,如果scriptEnv元表里没找到想要的值,就在__index里找
this.meta = luaEnv.NewTable();
meta.Set("__index", luaEnv.Global);
}
}
加载LuaMonoBehaviour.lua脚本的代码
public LuaTable InitMonoBehaviour(XLuaMonoBehaviour xLuaMonoBehaviour)
{
Debug.Log("InitMonoBehaviour");
//新建一个表,并设置元表为上面定义的meta
luaTable = luaEnv.NewTable();
luaTable.SetMetaTable(meta);
//把xLuaMonoBehaviour对象传到lua侧
luaTable.Set("self", xLuaMonoBehaviour);
DoString(LoadLuaScript("Common/LuaMonoBehaviour"), "LuaMonoBehaviour", luaTable);
return luaTable;
}
///
/// 这里为了方便笔记,所以采用了C# IO来加载lua内容,只针对unity Editor
///
///
///
private string LoadLuaScript(string _filePath)
{
Debug.Log("LoadLuaScript "+_filePath);
string _scriptPath = string.Empty;
_filePath = _filePath.Replace(".", "/") + ".lua";
_scriptPath = Path.Combine(Application.dataPath, luaScriptsFolder);
_scriptPath = Path.Combine(_scriptPath, _filePath);
string str = FileManager.GetFileContent(_scriptPath);
// Debug.Log("LuaScript " + str);
return str;
}
///
/// 创建定义从C#到lua间的一个桥接,委托
///
///
///
///
public Action CallFunction(string _targetName, string _function)
{
return luaTable.Get<Action>(_function);
}
我会在文章后面附上完整的XLuaManager.cs类
5、现在加载lua脚本,建立桥接关系都已经搭好了,我们还需要在XLuaMonoBehaviour.cs 里创建委托映射,如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class XLuaMonoBehaviour : MonoBehaviour
{
private LuaTable luaTable;
private Action luaAwake;
private Action luaStart;
private Action luaUpdate;
private Action luaOnEnable;
private Action luaOnDestroy;
private void Awake()
{
this.luaTable = XLuaManager.GetInstance().InitMonoBehaviour(this);
luaAwake = CallLuaFunction("Awake");
luaStart = CallLuaFunction("Start");
luaUpdate = CallLuaFunction("Update");
luaOnEnable = CallLuaFunction("OnEnable");
luaOnDestroy = CallLuaFunction("OnDestroy");
luaAwake?.Invoke();
}
private Action CallLuaFunction(string _fun)
{
return XLuaManager.GetInstance().CallFunction(gameObject.name, _fun);
}
private void OnEnable()
{
luaOnEnable?.Invoke();
}
// Start is called before the first frame update
void Start()
{
luaStart?.Invoke();
}
// Update is called once per frame
void Update()
{
luaUpdate?.Invoke();
}
private void OnDestroy()
{
luaOnDestroy?.Invoke();
luaOnDestroy = null;
luaStart = null;
luaUpdate = null;
this.luaTable.Dispose();
}
}
6、这样,我们的功能都已经做好了,让我们来执行下吧
XLuaManager.GetInstance().StartUp();
XLuaManager.GetInstance().OnEntry();
GameObject.Find("Canvas/Button").AddComponent<XLuaMonoBehaviour>();
第一第二句主要是启动xlua的,第一章有介绍了。
第二句我在Canvas下的Button对象添加了一个XLuaMonoBehaviour.cs脚本。
执行效果如下:
这里打印的就是我们在lua文件里print的东西。我们可以看到执行顺序是跟C#端一样的。
后记:我是初学者,很多地方其实我也不是很懂,看了好久官方教程,还有官方的LuaBehaviour.cs类才写的了这个文章,在有些地方也说不出个所以然,只是照搬了做下笔记加深印象。如果说我有什么说的不对的地方,还望有哪位懂的大神指点下,多多纠正啊。
完整的XLuaManager.cs类发一次出来
using FileUtility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;
public class XLuaManager : MonoSingleton<XLuaManager>
{
//放置LuaScripts代码的文件夹名字
public const string luaScriptsFolder = "LuaScripts";
//lua代码的文件名
const string luaGameEntryScript = "LuaGameEntry";
private LuaEnv luaEnv = null;
private LuaTable luaTable = null;
private LuaTable meta = null;
// Start is called before the first frame update
void Start()
{
}
protected override void Init()
{
base.Init();
InitLuaEnv();
}
private void InitLuaEnv()
{
luaEnv = new LuaEnv();
if (luaEnv != null)
{
luaEnv.AddLoader(CustomLoader);
this.meta = luaEnv.NewTable();
meta.Set("__index", luaEnv.Global);
}
}
///
/// 回调中可以根据这个参数去加载指定文件
/// 如果需要支持调试,需要把filepath修改为真实路径传出。
/// 该回调返回值是一个byte数组,如果为空表示该loader找不到,否则则为lua文件的内容
///
///
///
public static byte[] CustomLoader(ref string _filePath)
{
string _scriptPath = string.Empty;
_filePath = _filePath.Replace(".", "/") + ".lua";
if (Application.platform == RuntimePlatform.WindowsEditor)
{
_scriptPath = Path.Combine(Application.dataPath, luaScriptsFolder);
_scriptPath = Path.Combine(_scriptPath, _filePath);
byte[] _bytes = FileManager.SafeReadAllBytes(_scriptPath);
return _bytes;
}
return null;
}
///
/// lua脚本启动入口
///
public void OnEntry()
{
if (luaEnv != null)
{
loadScript(luaGameEntryScript);
DoString("LuaGameEntry.Start()");
}
}
// Update is called once per frame
void Update()
{
}
private void loadScript(string _scriptName)
{
DoString(string.Format("require('{0}')", _scriptName));
}
///
/// 加载lua代码块
///
///
public void DoString(string _luaScript,string _chunkName="chunk",LuaTable _luaTable=null)
{
if (luaEnv != null)
{
try
{
luaEnv.DoString(_luaScript,_chunkName,_luaTable);
}
catch (System.Exception ex)
{
Debug.Log(ex.Message);
}
}
}
public LuaEnv GetLuaEnv()
{
return this.luaEnv;
}
public LuaTable InitMonoBehaviour(XLuaMonoBehaviour xLuaMonoBehaviour)
{
Debug.Log("InitMonoBehaviour");
//新建一个表,并设置元表为上面定义的meta
luaTable = luaEnv.NewTable();
luaTable.SetMetaTable(meta);
//把xLuaMonoBehaviour对象传到lua侧
luaTable.Set("self", xLuaMonoBehaviour);
DoString(LoadLuaScript("Common/LuaMonoBehaviour"), "LuaMonoBehaviour", luaTable);
return luaTable;
}
///
/// 这里为了方便笔记,所以采用了C# IO来加载lua内容,只针对unity Editor
///
///
///
private string LoadLuaScript(string _filePath)
{
Debug.Log("LoadLuaScript "+_filePath);
string _scriptPath = string.Empty;
_filePath = _filePath.Replace(".", "/") + ".lua";
_scriptPath = Path.Combine(Application.dataPath, luaScriptsFolder);
_scriptPath = Path.Combine(_scriptPath, _filePath);
string str = FileManager.GetFileContent(_scriptPath);
// Debug.Log("LuaScript " + str);
return str;
}
///
/// 创建定义从C#到lua间的一个桥接,委托
///
///
///
///
public Action CallFunction(string _targetName, string _function)
{
return luaTable.Get<Action>(_function);
}
}