unity lua属性绑定刷新

我们现在有一个 角色属性类叫heroModel,内容如下,当heroModel中的等级发生变化的时候,我们需要刷新界面显示等级信息,通常我们是在收到等级升级成功的协议的时候,发送一个事件,UI界面接受到这个事件的时候,刷新一下等级信息,如果不采用全局事件的方式,该怎么处理呢

我们能不能监听HeroModel的level这个属性,给这个属性绑定一个监听方法,当这个属性发生变化的时候,自动执行这个监听方法执行一些刷新操作。

lua 复制代码
local heroModel = {
        id = 1001,
        star = 1,
        level = 1, 
        life = 1000,
        atk = 100,
        def = 10,
    }
   

我们知道,lua有两个比较常见的原方法 __index 和 __newindex,__index是 元表提供的表对象内部数据获取元方法,__newindex是当对表中不存在的元素进行赋值时会被调用。当我们从heroModel中获取某一个属性值的时候,会先从heroModel中取值,如果heroModel中不存在该值,则会从原表中取值,同样当我们给heroModel赋值的时候,会先判断heroModel是否存在该属性,如果存在,直接赋值,不存在则从原方法 __newindex中进行赋值。加入heroModel中不存在level这个属性,那么我们给它赋值的时候,肯定会调用原方法__newindex ,这个时候我们就可以在这个原方法里面赋值的时候进行判断,属性level是否发生变化,如果发生了变化, 则执行一个回调方法

简单演示如下

lua 复制代码
local heroModel = {
         id = 1001, star = 1, level=1
     }

    ---创建原表
    local metaTable = {}
        metaTable.newInfo = {}  --保存新创建的属性值
        metaTable.bindDataList = {}  --存储回调方法
        metaTable.__index = function(t , k)
            printError("get " .. k)
            local res = metaTable.newInfo[k]
            return res
         end

        metaTable.__newindex = function(t, k, v)
            printError("set " .. k .. " = " .. tostring(v))
            if (not metaTable.newInfo[k] or metaTable.newInfo[k] ~= v) and metaTable.bindDataList[k] ~= nil then
                local callback = metaTable.bindDataList[k]
                callback()
            end
            metaTable.newInfo[k] = v
            return v
        end

    -- 将heroModel中的属性赋值到原表,并清空heroModel,这样操作之后,只要给heroModel进行赋值就会执行它的原方法 __newindex
     for k, v in pairs(heroModel) do
         metaTable.newInfo[k] = v
         heroModel[k] = nil
     end
    -- 设置元表
     setmetatable(heroModel, metaTable)

   -- 绑定回调方法
    metaTable.bindDataList["level"] = function()
        printError("level 值发生了变化")
    end

    --测试
    printError("----test---")
    printError("level 初始值 = "..tostring(heroModel.level)) --没有更新赋值时候进行调用
    heroModel.level = 10 --通过__newindex 刷新属性值,并执行回调
    heroModel.level = 11
    local b = heroModel.level --通关__index 获取新属性值
    printError("level新值 = " .. b)
    heroModel.kkk = 111 --通过__newindex 创建新属性值
    printError(heroModel.kkk) --通关__index 获取新属性值

输出结果

完整代码

lua 复制代码
DataBindModel = {}

---@class DataBindModel:nil
local DataBindModel = DataBindModel

---给实例添加绑定 内部方法 不要手动调用
---@param target dataBindInfo
function DataBindModel:__bindIns(target)
    if (target.dataBindvars) then
        return
    end
    local dataBindvars = {}
    local mateTable = getmetatable(target)
    setmetatable(dataBindvars, mateTable)

    for k, v in pairs(target) do
        dataBindvars[k] = v
        target[k] = nil
    end
    target.dataBindvars = dataBindvars
    target.bindInfo__ = {}
    target.isBind = false
    target.oldMateTable = mateTable
    local settable = { __index = function(t, key)
        return dataBindvars[key]
    end }
    settable.__newindex = DataBindModel.__newindex
    setmetatable(target, settable)
end

function DataBindModel:unBindIns(target)
    if (not target.dataBindvars) then
        return
    end
    local dataBindvars = target.dataBindvars
    local mateTable = target.oldMateTable
    target.oldMateTable = nil
    target.bindInfo__ = nil
    target.isBind = nil
    target.dataBindvars = nil
    setmetatable(target, mateTable)
    for k, v in pairs(dataBindvars) do
        target[k] = v
    end
end

function DataBindModel:newIndex(key)
    return self.dataBindvars[key]
end

function DataBindModel:__newindex(key, var)
    local vars = self.dataBindvars
    local oldValue = vars[key]
    vars[key] = var

    if (self.isBind) then

        if (oldValue ~= var) then
            local bindInfo__ = self.bindInfo__
            local bindData = bindInfo__[key]
            if (bindData) then
                local tempBindData = {}
                for i, bdata in ipairs(bindData) do
                    table.insert(tempBindData, bdata)
                end
                for i, bdata in ipairs(tempBindData) do
                    bdata.callBack(var, bdata, self)
                end
                tempBindData = nil
            end
        end
    end

end

---@param target any @model
---@param bindInfo dataBindInfo
function DataBindModel:bindKey(target, bindInfo)
    if not target then
        printWarningColor("FFB500FF", "dataModel is nil")
        return
    end

    if (not target.dataBindvars) then
        self:__bindIns(target)
    end
    local bindInfo__ = target.bindInfo__
    local bindData = bindInfo__[bindInfo.key]
    if (not bindData) then
        bindData = {}
        bindInfo__[bindInfo.key] = bindData
    end
    target.isBind = true
    local uiNode = bindInfo.uiNode
    if (uiNode and not tolua.isnull(uiNode)) then
        ---@type CS.NodeEventListener
        local nodeEventListener = uiNode:GetComponent(typeof(CS.NodeEventListener))
        if not nodeEventListener then
            nodeEventListener = uiNode.gameObject:AddComponent(typeof(CS.NodeEventListener))
            bindInfo.nodeEventHandle = function()
                self:unBindKey(target, bindInfo)
            end
            if nodeEventListener.destroyCallback then
                nodeEventListener.destroyCallback = nodeEventListener.destroyCallback + bindInfo.nodeEventHandle
            else
                nodeEventListener.destroyCallback = bindInfo.nodeEventHandle
            end
        end
    end
    table.insert(bindData, bindInfo)
end

---@param target any
---@param bindInfo dataBindInfo
function DataBindModel:unBindKey(target, bindInfo)
    if (not target.dataBindvars) then
        return
    end
    local bindInfo__ = target.bindInfo__
    local bindData = bindInfo__[bindInfo.key]
    if (bindData) then
        local index = table.indexof(bindData, bindInfo)
        if (index) then

            table.remove(bindData, index)
            local uiNode = bindInfo.uiNode
            if (uiNode and not tolua.isnull(uiNode)) then
                local nodeEventHandle = uiNode:GetComponent(typeof(CS.NodeEventListener))
                if nodeEventHandle then
                    nodeEventHandle.destroyCallback = nodeEventHandle.destroyCallback - bindInfo.nodeEventHandle
                end
            end
        end
        if (#bindData == 0) then
            bindInfo__[bindInfo.key] = nil
        end
    end
    local count = 0;
    for k, v in pairs(bindInfo__) do
        count = count + 1;
        break ;
    end
    if (count <= 0) then
        self:unBindIns(target)
    end
end

---@param bindDataInfos dataBindInfo
function DataBindModel:bindKeys(target, bindDataInfos)
    for i, data in ipairs(bindDataInfos) do
        self:bindKey(target, data)
    end
end

---@param bindDataInfos dataBindInfo
function DataBindModel:unBindKeys(target, bindDataInfos)
    for i, data in ipairs(bindDataInfos) do
        self:unBindKey(target, data)
    end
end

return DataBindModel

调用

注:DataBindModel 是一个全局table

lua 复制代码
local heroModel = {
         id = 1001, star = 1, level=1
     }
local bindDatas = {
	key = "level", 
	callBack = function(value, bindInfo, model)
		-- 执行刷新逻辑
		self:checkRed()
	end
}
DataBindModel:bindKeys(heroModel, bindDatas)
相关推荐
Aric_Jones5 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua
qq_59821175715 小时前
Unity.UGUI DrawCall合批笔记
笔记·unity·游戏引擎
Petrichorzncu20 小时前
Lua再学习
开发语言·学习·lua
mikey棒棒棒1 天前
lua脚本+Redission实现分布式锁
redis·分布式·lua·看门狗·redission
Tech Synapse1 天前
Unity ML-Agents实战指南:构建多技能游戏AI训练系统
人工智能·游戏·unity
咩咩觉主2 天前
c#数据结构 线性表篇 非常用线性集合总结
开发语言·数据结构·unity·c#·游戏引擎·程序框架
weixin_428498492 天前
在Lua中使用轻量级userdata在C/C++之间传递数据和调用函数
c语言·c++·lua
浅陌sss2 天前
Unity中AssetBundle使用整理(一)
unity·游戏引擎
KhalilRuan3 天前
Unity-Shader详解-其五
unity·游戏引擎
惊鸿醉3 天前
Unity C# 中的 反射 小记
unity·c#·游戏引擎