ULUA的简洁用法(二)

来源:互联网 发布:手机处理数据软件 编辑:程序博客网 时间:2024/06/04 08:08

《ULUA的简洁用法(二)》
作者: 游蓝海
文章链接:http://blog.csdn.net/you_lan_hai/article/details/70554237
转载请注明出处

写上一篇文章《ULUA简洁用法》的时候,我对ULUA的认识还不是很深,经过一段时间的摸索后,我又整理了另一种更简单的方式,不需要修改ULUA源码,一个代码文件就能容纳下所有需要的内容。

1.原理

给GameObject添加上一个C#脚本组件作为中间层,在中间层上绑定上一个LUA脚本,将Unity的所有回调接口通过中间层传递到LUA。同时,LUA脚本也可以通过中间层操作GameObject。

2.实现中间层LuaBehaviour

中间层从MonoBehaviour派生

添加public变量ScriptName,用于在编辑器属性界面中输入Lua的模块名。当中间层Awake的时候,根据ScriptName加载Lua文件,并实例化出Lua类对象。

实例化LuaClient

LuaClient在整个工程中应当只存在一个实例对象,我们可以把他绑定到一个不随关卡销毁的GameObject对象上(调用了DontDestroyOnLoadGameObject)。我们可以把实例化步骤也放到中间层脚本上,如此一来,只要场景中挂载了中间层脚本,LuaClient也就会被自动初始化。

调用成员方法

对于只调用一次的Lua层方法,我们没必要在C#端去记录这个成员变量,比如Lua层面的AwakeStart方法。为了方便使用,我们在需要自动将self作为第一个参数,传递给Lua方法。

object[] CallMethod(string func, params object[] args)

中间层关键代码

using UnityEngine;using System;using System.Collections;using LuaInterface;public class LuaBehaviour : MonoBehaviour{    public string           ScriptName;    protected LuaState      luaState_;    protected LuaTable      self_;    public LuaTable script    {        get{ return self_; }    }    protected void Awake()    {        // 这一步会触发LuaClient实例化。        luaState_ = GetMainLuaState();        if (ScriptName != null && ScriptName != null)        {            loadScript(ScriptName);            //尝试调用脚本对象的Awake函数            CallMethod("Awake");        }    }    // 根据Lua模块名,加载Lua脚本    public bool loadScript(string scriptName)    {        if (scriptName == null)        {            Debug.LogError("The ScriptName must be set.");            return false;        }        ScriptName = scriptName;        // require lua文件,得到返回的类        LuaTable metatable = (LuaTable)require(ScriptName);        if (metatable == null)        {            Debug.LogError("Invalid script file '" + ScriptName + "', metatable needed as a result.");            return false;        }        // 从类中找到New函数        LuaFunction lnew = (LuaFunction)metatable["New"];        if (lnew == null)        {            Debug.LogError("Invalid metatable of script '" + ScriptName + "', function 'New' needed.");            return false;        }        //执行New函数生成脚本对象        object[] results = lnew.Call(metatable);        if (results == null || results.Length == 0)        {            Debug.LogError("Invalid 'New' method of script '" + ScriptName + "', a return value needed.");            return false;        }        //存贮脚本对象        bindScript((LuaTable)results[0]);        return true;    }    // 将一个已经存在的Lua对象绑定到当前组件中。    // 用于在脚本中动态创建对象,并手动挂接Lua对象。    public void bindScript(LuaTable script)    {        self_ = script;        //给脚本对象设置上常用的属性        self_["transform"] = transform;        self_["gameObject"] = gameObject;        self_["behaviour"] = this;    }    // 调用Lua端的成员方法。会自动将self作为第一个参数,传递到Lua。    protected object[] CallMethod(string func, params object[] args)    {        if (self_ == null)        {            return null;        }        LuaFunction lfunc = (LuaFunction)self_[func];        if (lfunc == null)        {            return null;        }        //等价于lua语句: self:func(...)        int oldTop = lfunc.BeginPCall();        lfunc.Push(self_);        lfunc.PushArgs(args);        lfunc.PCall();        object[] objs = luaState_.CheckObjects(oldTop);        lfunc.EndPCall();        return objs;    }    // 自己实现一个lua require函数,可以得到require的返回值。    public object require(string fileName);    // 这个函数是实例化LuaClient的入口。代码中获取LuaClient都调用这个静态函数。    public static LuaClient GetLuaClient()    {        if (LuaClient.Instance == null)        {            Debug.Log("LuaBehaviour create LuaClient");            GameObject obj = new GameObject();            obj.name = "LuaClient";            // 绑定LuaClient组件            obj.AddComponent<LuaClient>();            // 让obj常驻内存,不自动卸载            DontDestroyOnLoad(obj);        }        return LuaClient.Instance;    }    public static LuaState GetMainLuaState()    {        GetLuaClient();        return LuaClient.GetMainState();    }}

完整代码看这里

3.添加LUA脚本层

在Assets/Lua目录下新建LUA脚本Test.lua,核心代码如下:

--构造Test类local Test = {}Test.__index = Test --让实例对象的__get方法指向Test类--给Test类实例化一个对象function Test.New(cls)    local self = {}    setmetatable(self, cls)    return selfend--Awake方法function Test:Awake()    print("Test:Awake", self)end--将类Test返回。通过require函数的返回值就可以获取到此值了。return Test

4.测试

完整代码地址:https://github.com/youlanhai/tolua

下载代码后,用Unity打开Test2.unity工程,执行一次菜单Lua/Generate All。然后点击运行,会看到一个上下运动的立方体。

5.总结

相比于上一篇文章,这一次只手动实现了一个C#类,不需要额外的辅助代码,也不需要修改ToLua的源码。代码更容易集成到最新的ToLua源码中。

0 0