关于Lua的Unity UI面向过程编程模板

关于Lua的Unity UI面向过程编程模板

该模板基于xLua实现,对xLua不熟悉的可以去了解下。改用别的Lua热更方案也容易。

先发下示例地址

https://github.com/skylecn/xLua/tree/master/Assets/XLua/Examples/UIFrame

窗口如下

关于Lua的Unity UI面向过程编程模板_第1张图片
窗口左侧是一个列表,选择列表中的项,右边会显示当前选择项的内容。

下面是实现窗口功能的Lua文件。

require 'item'  --列表项

local ue = CS.UnityEngine

--窗口
Panel = {
    --Awake事件
    --data是一个table,其中包含该UI的gameObject和注册的UI组件,也可以增加自己的变量
    Awake = function (data)
        data.list = {}; --保存生成的Item的data
        local go = ue.Resources.Load('Item')
        for index=1,3 do
            local item = ue.Object.Instantiate(go)
            item.transform.parent = data.leftView.transform
            item.transform.localScale = ue.Vector3.one
            data.list[index] = item:GetComponent('FuncLuaBehavior').luaData
            Item.Init(data.list[index], data, index)
        end
    end;

    --选择某项
    SelectItem = function (data, num)
        for index= 1, #data.list do
            data.num:GetComponent('Text').text=num
            Item.SetLight(data.list[index], index==num and true or false)
        end
    end;
}

在以上文件中只定义了两个函数,数据data作为函数参数被处理,这就是面向过程的编程方式。那data具体是什么?又是如何被定义的呢?看下面的代码。

[LuaCallCSharp]
public class FuncLuaBehavior : MonoBehaviour {
    public string luaFile;
    public Injection[] injections;

    internal static LuaEnv luaEnv = new LuaEnv(); //all lua behaviour shared one luaenv only!

    LuaTable dataTable; // Lua table,包括C#创建的和Lua中创建的数据

    LuaTable funcTable; // Lua实现的事件响应函数和功能函数

    public LuaTable luaData
    {
        get { return dataTable; }
    }

    void Awake()
    {
        //加载Lua文件
        luaEnv.DoString(string.Format("require '{0}'", luaFile ));

        //定义dataTable
        dataTable = luaEnv.NewTable();
        //插入需要处理的UI组件到dataTable中
        dataTable.Set("gameObject", gameObject);
        foreach (var injection in injections)
        {
            dataTable.Set(injection.name, injection.value);
        }

        //获取Lua文件中函数table的引用
        funcTable = luaEnv.Global.Get(luaFile);
        if (funcTable != null)
        {
            var luaAwake = funcTable.Get>("Awake");
            if (luaAwake != null)
            {
                luaAwake(dataTable);
            }
        }
    }
}

上面代码部分借鉴了xLua中LuaBehaviour的实现,面向过程的支持主要是dataTable和funcTable。dataTable即该窗口的“数据”,在Awake中创建并插入需要处理的UI组件。funcTable引用在Lua文件定义的table,也就是我们先前的Lua文件。然后我们触发Lua中的Awake事件,事件的参数就是dataTable。

这就是整个模板的结构。

以下是该示例另一部分Lua文件,结合代码中的注释来理解整个实现。

local ue = CS.UnityEngine

--列表项
Item = {
    --Awake事件
    Awake = function (data)
        data.button:GetComponent("Button").onClick:AddListener(function()
            Panel.SelectItem(data.panel, data._num)
        end)
    end;

    --初始化
    Init = function (data, panel, num)
        data.panel = panel  --保存父窗口引用
        data._num = num --保存编号
        data.num:GetComponent("Text").text = num
    end;

    --设置选中状态
    SetLight = function (data, light)
        data.light:SetActive(light)
    end;
}

为什么不面向对象,而要面向过程?

  • 面向过程比面向对象简单清晰,容易上手,而UI功能也比较简单,就是事件响应,用面向过程就可以解决问题
  • Lua的面向对象基于metatable实现,写一个类声明就需要好多行代码,相比高级语言的class声明还复杂
  • Lua中定义的变量的作用域有全局和当前文件,但只能对应一个C#对象,如果C#的多个对象,就需要定义多个变量与之对应,实现背包这样的功能比较麻烦。使用面向过程,数据和功能分离,Lua中实现功能,数据由C#定义和管理。数据和UI组件的生命周期对应,Awake时定义,OnDestroy时销毁。数据作为参数递到Lua事件,在Lua事件响应中处理对应的UI组件。

你可能感兴趣的:(unity,lua)