Lua写MonoBehaviour


CS:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using XLua;
 
// 注入Lua的数据
[System.Serializable]
public class Injection
{
    public string name;
    public GameObject value;
}
 
public class SceneManager : MonoBehaviour
{
    public TextAsset luaScript; // Lua脚本
    public Injection[] injections;
 
    internal static LuaEnv luaEnv = new LuaEnv(); // 全局唯一的Lua环境
 
    private LuaTable scriptEnv; // 脚本环境
 
    internal static float lastGCTime = 0;
    internal const float GCInterval = 1; // 垃圾回收间隔?
 
    // 在Lua端定义的函数
    private Action luaStart;
    private Action luaUpdate;
    private Action luaOnDestroy;
 
    private void Awake()
    {
        Debug.Log("CS Awake");
 
        scriptEnv = luaEnv.NewTable();
 
        // 设置元表这一步是必需的
        LuaTable meta = luaEnv.NewTable(); // 元表
        meta.Set("__index", luaEnv.Global); // 元表的__index是Lua全局环境,这样才能访问到print这样的函数
        scriptEnv.SetMetaTable(meta); // 设置元表
        meta.Dispose(); // 在这里就直接弃用吗?
 
        // 注入数据:设置在Lua端能够读取到的数据
        scriptEnv.Set("self", this);
        scriptEnv.Set("Key", 19437); // 随便传递一个数据进去,在Lua端就能读取到
        foreach (var injection in injections)
        {
            scriptEnv.Set(injection.name, injection.value);
        }
 
        // Lua脚本也像CS的MonoBehaviour一样写,没有入口代码,都是函数定义
        luaEnv.DoString(luaScript.text, luaScript.name, scriptEnv);
 
        // Lua的脚本环境有值之后,就可以获取函数并绑定了
        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();
        }
    }
 
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("CS Start");
 
        /*
        // 一个最简单的例子
 
        XLua.LuaEnv luaenv = new XLua.LuaEnv(); // 一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一
        luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
        luaenv.Dispose();
        */
 
        if (luaStart != null)
        {
            luaStart();
        }
    }
 
    // Update is called once per frame
    void Update()
    {
        if (luaUpdate != null)
        {
            luaUpdate();
        }
 
        if (Time.time - SceneManager.lastGCTime > GCInterval)
        {
            luaEnv.Tick(); // 这样就能触发Lua的GC吗?
            SceneManager.lastGCTime = Time.time;
        }
    }
 
    void OnDestroy()
    {
        if (luaOnDestroy != null)
        {
            luaOnDestroy();
        }
        // 清空Action绑定
        luaOnDestroy = null;
        luaUpdate = null;
        luaStart = null;
        // 销毁脚本环境
        scriptEnv.Dispose();
        injections = null;
    }
}

Lua:

-- Lua端定义的函数都是全局的
 
function awake()
    print("lua awake...")
end
 
function start()
    print("lua start...")
    print('Key = '..Key)
end
 
function update()
 
end
 
function ondestroy()
    print("lua destroy...")
end