在前面的文章里面我们已经介绍了怎么样在unity里面配置lua的开发环境,我们可以通过C#代码装载lua的脚本并执行相应的处理,这次我们一步步搭建下lua的开发体系。
1.基于c#体系所有的类都继承MonoBehaviour在这里lua环境下我们也需要创建一个类似于这个类的东西,我们叫这个类LuaBehaviour在这个类里面我们提供了transform及object的实例
lua
local LuaBehaviour = {}
function LuaBehaviour:new(instant)
if not instant then
instant = {} --类的实例
end
setmetatable(instant, {__index = self})
return instant
end
-- 返回一个基类为base的类;
function LuaExtend(base)
return base:new()
end
function LuaBehaviour:init(obj)
self.transform = obj.transform
self.gameObject = obj
end
return LuaBehaviour
这里面提供三个方法 new方法创建实例对象,init创建实例化对象后初始化游戏要用到,最后一个方法可以理解为继承后面我们会介绍到。
2.上面的init方法我们可以看到有两个对象transform以及gameobject这两个对象是怎么来的可以看到transform是gameobject点出来的,那我们是不是需要一个gameobject的基类我们叫做LuaGameObject
类代码如下
lua
LuaGameObject = {}
local GameObject = CS.UnityEngine.GameObject
local GameObjectMap = {}
-- key ObjectID: {lua组件实例1, Lua组件实例2, ...};
local function Instantiate(prefab)
GameObject.Instantiate(prefab)
end
local function Destroy(obj)
local obj_id = obj:GetInstanceID()
if (GameObjectMap[obj_id]) then -- 删除掉所有的组件实例
table.remove(GameObjectMap, obj_id)
end
GameObject.Destroy(obj)
end
local function Find(name)
return GameObject.Find(name)
end
local function AddLuaComponent(obj, lua_class)
local componet = lua_class:new()
componet:init(obj)
local obj_id = obj:GetInstanceID()
if (GameObjectMap[obj_id]) then
table.insert(GameObjectMap[obj_id], componet)
else
GameObjectMap[obj_id] = {}
table.insert(GameObjectMap[obj_id], componet)
end
if componet.Awake ~= nil then
componet:Awake()
end
return componet
end
local function trigger_update(components_array)
local key, value
for key, value in pairs(components_array) do
if value.Update ~= nil then
value:Update()
end
end
end
local function trigger_fixupdate(components_array)
local key, value
for key, value in pairs(components_array) do
if value.FixedUpdate ~= nil then
value:FixedUpdate()
end
end
end
local function trigger_lateupdate(components_array)
local key, value
for key, value in pairs(components_array) do
if value.LateUpdate ~= nil then
value:LateUpdate()
end
end
end
local function Update()
local key, value
for key, value in pairs(GameObjectMap) do
trigger_update(value)
end
end
local function FixedUpdate()
local key, value
for key, value in pairs(GameObjectMap) do
trigger_fixupdate(value)
end
end
local function LateUpdate()
local key, value
for key, value in pairs(GameObjectMap) do
trigger_lateupdate(value)
end
end
LuaGameObject.Update = Update
LuaGameObject.LateUpdate = LateUpdate
LuaGameObject.FixedUpdate = FixedUpdate
LuaGameObject.Find = Find
LuaGameObject.Instantiate = Instantiate
LuaGameObject.Destroy = Destroy
LuaGameObject.AddLuaComponent = AddLuaComponent
return LuaGameObject
上面我们提供了几个方法有需要的话可以继续添加方法以满足开发的需要。 Find函数负责找到我们需要的GameObject,Instantiate用过预制体的伙伴都熟悉这个函数负责实例化对象用的,Destroy不用说销毁对象用的这里需要注意的是我们表里面跟这个对象挂钩的数据也要一并清理掉。AddLuaComponent这块是重点我们处理逻辑是将脚本实例化,并调用init方法初始化object以及transform跟上面的LuaBehaviour脚本对应上了,将脚本存放到表中去,这样做的目的主要是在update里面调用脚本上面的update函数等等。
3.假如我们需要通过lua控制一个物体不断移动我们试着建立一个脚本叫做cube_ctrl继承LuaBehaviour
lua
local LuaBehaviour = require("Component.LuaBehaviour")
local cube_ctrl = LuaExtend(LuaBehaviour)
function cube_ctrl:Awake()
print("========Awake=========")
end
function cube_ctrl:Update()
self.transform:Translate(0, 0, 5 * CS.UnityEngine.Time.deltaTime)
end
return cube_ctrl
4.我们添加一个场景游戏启动类
lua
local start = {}
local cube_ctrl = require("game.cube_ctrl")
local function enter_login_scene()
print("enter_login_scene")
local obj = LuaGameObject.Find("Cube")
LuaGameObject.AddLuaComponent(obj, cube_ctrl)
end
local function enter_game_scene()
end
local function init()
enter_login_scene()
end
start.init = init
return start;
这个类的处理也是很简单定义了一个初始化方法初始化的时候调用enter_login_scene方法这里面找到了场景中物体Cube然后给这个物体添加脚本,这样update处理就能处理到这些脚本的update方法
5.最后的处理将我们这些造好的轮子驱动起来,如何驱动这些脚本回到我们的main方法中去
lua
require("managers.LuaGameObject")
local game = require("game.start")
main = {} -- main是一个全局模块;
local function start()
game.init();
end
local function Update()
LuaGameObject.Update()
end
local function FixedUpdate()
LuaGameObject.FixedUpdate()
end
local function LateUpdate()
LuaGameObject.LateUpdate()
end
main.Update = Update
main.FixedUpdate = FixedUpdate
main.LateUpdate = LateUpdate
main.start = start
return main
最后是C#调用代码代码如下
csharp
using UnityEngine;
using XLua;
public class LuaLoader : MonoBehaviour
{
private LuaEnv luaEnv = null;
void Start()
{
luaEnv = new LuaEnv();
luaEnv.AddLoader(MyLuaLoader);
LoadScript("main");
SafeDoString("main.start()");//执行脚本
}
void Update()
{
SafeDoString("main.Update()");
}
void FixedUpdate()
{
SafeDoString("main.FixedUpdate()");
}
void LateUpdate()
{
SafeDoString("main.LateUpdate()");
}
public static byte[] MyLuaLoader(ref string filePath)
{
string scriptPath = string.Empty;
filePath = filePath.Replace(".", "/") + ".lua";
scriptPath += Application.dataPath + "/LuaScripts/" + filePath;
return GameUtility.SafeReadAllBytes(scriptPath);//通过文件IO读取lua内容
}
public void LoadScript(string scriptName)
{
SafeDoString(string.Format("require('{0}')", scriptName));
}
public void SafeDoString(string scriptContent)
{ // 执行脚本, scriptContent脚本代码的文本内容;
if (this.luaEnv != null)
{
try
{
luaEnv.DoString(scriptContent); // 执行我们的脚本代码;
}
catch (System.Exception ex)
{
string msg = string.Format("xLua exception : {0}\n {1}", ex.Message, ex.StackTrace);
Debug.LogError(msg, null);
}
}
}
}
场景也是极其简单在场景放一个cube即可