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)
相关推荐
monstercl3 小时前
Lua中基础函数使用详解
lua·脚本语言
爱的叹息3 小时前
Spring Boot 集成Redis 的Lua脚本详解
spring boot·redis·lua
与火星的孩子对话3 小时前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
向宇it3 小时前
【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍
开发语言·游戏·unity·c#·编辑器·游戏引擎
牙膏上的小苏打233320 小时前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
Unity大海1 天前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
浅陌sss1 天前
Unity中 粒子系统使用整理(一)
unity·游戏引擎
维度攻城狮1 天前
实现在Unity3D中仿真汽车,而且还能使用ros2控制
python·unity·docker·汽车·ros2·rviz2
为你写首诗ge1 天前
【Unity网络编程知识】FTP学习
网络·unity
神码编程2 天前
【Unity】 HTFramework框架(六十四)SaveDataRuntime运行时保存组件参数、预制体
unity·编辑器·游戏引擎