using UnityEngine; using System.Collections; using LuaInterface; /// <summary> /// Lua组件 - 它调用的Lua脚本可以实现类似MonoBehaviour派生类的功能 /// </summary> [AddComponentMenu("Lua/LuaComponent")] public class LuaComponent : MonoBehaviour { private static LuaState s_luaState; // 全局的Lua虚拟机 [Tooltip("绑定的LUA脚本路径")] public TextAsset m_luaScript; public LuaTable LuaModule { get; private set; } LuaFunction m_luaUpdate; // Lua实现的Update函数,可能为null /// <summary> /// 找到游戏对象上绑定的LUA组件(Module对象) /// </summary> public static LuaTable GetLuaComponent(GameObject go) { LuaComponent luaComp = go.GetComponent<luacomponent>(); if (luaComp == null) return null; return luaComp.LuaModule; } /// <summary> /// 向一个GameObject添加一个LUA组件 /// </summary> public static LuaTable AddLuaComponent(GameObject go, TextAsset luaFile) { LuaComponent luaComp = go.AddComponent<luacomponent>(); luaComp.Initilize(luaFile); // 手动调用脚本运行,以取得LuaTable返回值 return luaComp.LuaModule; } /// <summary> /// 提供给外部手动执行LUA脚本的接口 /// </summary> public void Initilize(TextAsset luaFile) { m_luaScript = luaFile; RunLuaFile(luaFile); //-- 取得常用的函数回调 if (this.LuaModule != null) { m_luaUpdate = this.LuaModule["Update"] as LuaFunction; } } /// <summary> /// 调用Lua虚拟机,执行一个脚本文件 /// </summary> void RunLuaFile(TextAsset luaFile) { if (luaFile == null || string.IsNullOrEmpty(luaFile.text)) return; if (s_luaState == null) s_luaState = new LuaState(); object[] luaRet = s_luaState.DoString(luaFile.text, luaFile.name, null); if (luaRet != null && luaRet.Length >= 1) { // 约定:第一个返回的Table对象作为Lua模块 this.LuaModule = luaRet[0] as LuaTable; } else { Debug.LogError("Lua脚本没有返回Table对象:" + luaFile.name); } } // MonoBehaviour callback void Awake() { RunLuaFile(m_luaScript); CallLuaFunction("Awake", this.LuaModule, this.gameObject); } // MonoBehaviour callback void Start() { CallLuaFunction("Start", this.LuaModule, this.gameObject); } // MonoBehaviour callback void Update() { if (m_luaUpdate != null) m_luaUpdate.Call(this.LuaModule, this.gameObject); } /// <summary> /// 调用一个Lua组件中的函数 /// </summary> void CallLuaFunction(string funcName, params object[] args) { if (this.LuaModule == null) return; LuaFunction func = this.LuaModule[funcName] as LuaFunction; if (func != null) func.Call(args); } } </luacomponent></luacomponent>
require "EngineMain" local demoComponent = {} function demoComponent:Awake( gameObject ) Debug.Log(gameObject.name.."Awake") end return demoComponent
基于以上结构,就很容易实现Lua组件之间的互相调用。在Demo工程中,有一个“Sphere”对象,绑定了如下脚本:
require "EngineMain" local sphereComponent = {} sphereComponent.text = "Hello World" function sphereComponent:Awake( gameObject ) Debug.Log(gameObject.name.."Awake") end return sphereComponent
require "EngineMain" local demoComponent = {} function demoComponent:Awake( gameObject ) Debug.Log(gameObject.name.."Awake") end function demoComponent:Start( gameObject ) Debug.Log(gameObject.name.."Start") --演示LuaComponent代码互相调用 local sphereGO = GameObject.Find("Sphere") local sphereLuaComp = LuaComponent.GetLuaComponent(sphereGO) Debug.log("Sphere.LuaDemoB:"..sphereLuaComp.text) end return demoComponent最后,顺带总结一下:在设计上次游戏逻辑框架时,比较好的思路是:在透彻的理解Unity自身架构的前提下,在其架构下进行下一层设计,而不是想一种新的框架。因为Unity本身就是一个框架。