美文网首页
Unity3D热更新LuaFramework入门实战(4)——L

Unity3D热更新LuaFramework入门实战(4)——L

作者: EndIess | 来源:发表于2018-09-13 15:02 被阅读0次

原文链接:http://blog.sina.com.cn/s/blog_6788cd880102wbc0.html

基于组件的编程模式是Unity3D的核心思想之一,然而使用纯lua编程,基本就破坏了这一模式。那么有没有办法做一些封装,让Lua脚本也能挂载到游戏物体上,作为组件呢?

By 知乎@罗培羽

2016年6月

1、设计思想

在需要添加Lua组件的游戏物体上添加一个LuaComponent组件,LuaComponent引用一个lua表,这个lua表包含lua组件的各种属性以及Awake、Start等函数,由LuaComponent适时调用Lua表所包含的函数。

下面列举lua组件的文件格式,它包含一个表(如Component),这个表包含property1 、property2 等属性,包含Awake、Start等方法。表中必须包含用于派生对象的New方法,它会创建一个继承自Component的表o,供LuaComponent调用。

Component=--组件表

​{

        property1 = 100,

property2 =“helloWorld”

}

 function Component:Awake() 

        print("TankCmp Awake name = "..self.name );

end

function Component:Start() 

        print("TankCmp Start name = "..self.name );

End

--更多方法略

function Component:New(obj) 

        local o = {} 

        setmetatable(o, self)  

        self.__index = self  

        return o

end  

2、LuaComponent组件

LuaComponent主要有Get和Add两个静态方法,其中Get相当于UnityEngine中的GetComponent方法,Add相当于AddComponent方法,只不过这里添加的是lua组件不是c#组件。每个LuaComponent拥有一个LuaTable(lua表)类型的变量table,它既引用上述的Component表。

Add方法使用AddComponent添加LuaComponent,调用参数中lua表的New方法,将其返回的表赋予table。

Get方法使用GetComponents获取游戏对象上的所有LuaComponent(一个游戏对象可能包含多个lua组件,由参数table决定需要获取哪一个),通过元表地址找到对应的LuaComponent,返回lua表。代码如下:

using UnityEngine;

using System.Collections;

using LuaInterface;

using LuaFramework;

public class LuaComponent : MonoBehaviour

{

        //Lua表

        public LuaTable table;

        //添加LUA组件  

        public static LuaTable Add(GameObject go, LuaTable tableClass)  

        {  

                LuaFunction fun = tableClass.GetLuaFunction("New");

                if (fun == null)

                        return null;

                object[] rets = fun.Call (tableClass);

                if (rets.Length != 1)

                        return null;

                LuaComponent cmp = go.AddComponent();  

                cmp.table = (LuaTable)rets[0];

                cmp.CallAwake ();

                return cmp.table;

        }  

        //获取lua组件

        public static LuaTable Get(GameObject go,LuaTable table)  

        {  

                LuaComponent[] cmps = go.GetComponents();  

                foreach (LuaComponent cmp in cmps)

                {

                        string mat1 = table.ToString();

                        string mat2 = cmp.table.GetMetaTable().ToString();

                        if(mat1 == mat2)

                        {

                                return cmp.table;

                        }        

                }

                return null;  

        }  

        //删除LUA组件的方法略,调用Destory()即可  

        void CallAwake ()

        {

                LuaFunction fun = table.GetLuaFunction("Awake");

                if (fun != null)

                        fun.Call (table, gameObject);

        }

        void Start ()

        {

                LuaFunction fun = table.GetLuaFunction("Start");

                if (fun != null)

                fun.Call (table, gameObject);

        }

        void Update ()

        {

                //效率问题有待测试和优化

                //可在lua中调用UpdateBeat替代

                LuaFunction fun = table.GetLuaFunction("Update");

                if (fun != null)

                fun.Call (table, gameObject);

        }

        void OnCollisionEnter(Collision collisionInfo)

        {

                //略

        }

    //更多函数略

}

3、调试LuaCompomemt

现在编写名为TankCmp的lua组件,测试LuaCompomemt的功能,TankCmp会在Awake、Start和Update打印出属性name。TankCmp.lua的代码如下:

TankCmp =

{

        --里面可以放一些属性

        Hp = 100,

        att = 50,

        name = "good tank",

}

function TankCmp:Awake()

        print("TankCmp Awake name = "..self.name );

end

function TankCmp:Start()

        print("TankCmp Start name = "..self.name );

end

function TankCmp:Update()

        print("TankCmp Update name = "..self.name );

end

--创建对象

function TankCmp:New(obj)

        local o = {}

       setmetatable(o, self)  

       self.__index = self  

      return o

end  

编写Main.lua,给游戏对象添加lua组件。

require "TankCmp"

--主入口函数。从这里开始lua逻辑

function Main()

        --组件1

        local go = UnityEngine.GameObject ('go')

        local tankCmp1 = LuaComponent.Add(go,TankCmp)

        tankCmp1.name = "Tank1"

        --组件2

        local go2 = UnityEngine.GameObject ('go2')

        LuaComponent.Add(go2,TankCmp)

        local tankCmp2 = LuaComponent.Get(go2,TankCmp)

        tankCmp2.name = "Tank2"

end

运行游戏,即可看到lua组件的运行结果:

程序运行结果

程序运行结果

4、坦克组件

下面代码演示用lua组件实现“用键盘控制坦克移动”的功能,TankCmp.lua的代码如下:

TankCmp =

{

        name = "good tank",

}

function TankCmp:Update(gameObject)

        print("TankCmp Update name = "..self.name );

        local Input = UnityEngine.Input;

        local horizontal = Input.GetAxis("Horizontal");

        local verticla = Input.GetAxis("Vertical");

        local x = gameObject.transform.position.x + horizontal

        local z = gameObject.transform.position.z + verticla

        gameObject.transform.position = Vector3.New(x,0,z)

end

--创建对象

function TankCmp:New(obj)

local o = {}

        setmetatable(o, self)  

        self.__index = self  

        return o

end  

Main.lua先加载坦克模型,然后给他添加lua组件,代码如下:

require "TankCmp"

--主入口函数。从这里开始lua逻辑

function Main()

        LuaHelper = LuaFramework.LuaHelper;

        resMgr = LuaHelper.GetResManager();

        resMgr:LoadPrefab('tank', { 'TankPrefab' }, OnLoadFinish);

end

--加载完成后的回调--

function OnLoadFinish(objs)

        go = UnityEngine.GameObject.Instantiate(objs[0]);

        LuaComponent.Add(go,TankCmp)

end

运行游戏,即可用键盘的控制坦克移动。

坦克组件运行结果

相关文章

网友评论

      本文标题:Unity3D热更新LuaFramework入门实战(4)——L

      本文链接:https://www.haomeiwen.com/subject/xbbwgftx.html