zoukankan      html  css  js  c++  java
  • ULUA的简洁用法(二)

    《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 self
    end
    
    --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源码中。

  • 相关阅读:
    小菜菜mysql练习50题解析——数据准备
    C语言(数据结构)——概述
    运行 jar
    Hive 语句
    java14 IO流缓冲区 input output
    java 14 IO流
    java 14 图片的读取和写入
    java 集合的基础2
    java 13 hashmao的entryset()
    java 13 集合的基础
  • 原文地址:https://www.cnblogs.com/ygxsk/p/7693970.html
Copyright © 2011-2022 走看看