首页 / 技术文章地图 / 正文

【界面UI】红点系统与面板刷新:UI 状态驱动设计

发布:2026-09-20 07:58 | 作者:996 技术组 | 3 阅读
完整课程入口:996 全套课程体系Lua 学习路径幂尔框架 mirs.cn

红点为什么容易写崩

红点是留存利器,也是 UI 层最容易写乱的功能:每个系统各写一套红点逻辑,按钮点击后忘了通知其他红点,红点闪烁与实际状态对不上。问题的根源是把"红点"当成了各界面自己的私事。正确做法是把红点抽成独立的状态驱动系统:红点只是数据的一种渲染,数据变了红点自然变。

红点树:一个表驱动的实现

把所有红点按界面层级组织成树:根节点"主界面"下挂"背包""任务""商城",背包下又挂"可穿戴""可出售"。叶子节点的红亮条件是一个注册进来的检测函数,父节点红亮 = 任意子节点红亮。数值变化时只重算受影响的一条链:

lua
local RP = { nodes = {} }

function RP.reg(id, parent, check)
    RP.nodes[id] = { parent = parent, check = check, on = false }
end

function RP.refresh(id)
    local n = RP.nodes[id]
    local on = n.check and n.check() or false
    if not on then
        for _, child in pairs(RP.nodes) do
            if child.parent == id and child.on then on = true break end
        end
    end
    if n.on ~= on then
        n.on = on
        UIsetIcon(id, on)            -- 实际点亮/熄灭
        if n.parent then RP.refresh(n.parent) end
    end
end

数据变化处只需调一句 RP.refresh("bag"),整条链自动联动,任何界面都不需要自己维护红点状态。

刷新原则:状态驱动而非事件驱动

面板刷新同理。新手常写"领奖励 → 调刷新背包 → 调刷新任务 → 调刷新主界面",每加一个系统就要往所有相关事件里插刷新调用,漏一处就出"数字不对"的 bug。状态驱动的做法:界面显示时从数据源全量刷新一次,数据层变更后广播"某数据变了"事件,订阅者各自刷新——界面永远反映数据的当前真实状态,不存在"忘了通知谁"。

性能上注意两点:高频数据(血量)的刷新做合并,一帧内多次变更只渲染一次;面板不可见时只更新数据不刷新控件,打开时全量刷一遍。

排查口诀

红点不亮/常亮,按固定顺序查三步:检测函数的输入数据对不对(打印 check 结果)→ refresh 是否被正确触发(在 refresh 加计数日志)→ 父节点聚合逻辑是否覆盖了该子节点。状态驱动的系统里,问题永远落在"数据、订阅、聚合"三点之一,比在十几个界面文件里翻事件调用快得多。

红点增删

reddot(actor, win_id, btn_id, x, y, type, info)

给按钮增加红点,数据层状态变化时由统一入口写红点,界面不自己判断

参数类型说明
actorobject玩家对象(必填参数)
win_idinteger窗口ID(必填参数)
btn_idinteger按钮ID/任务栏填任务ID(必填参数)
xintegerX坐标(必填参数)
yintegerY坐标(必填参数)
typeinteger红点模式0=图片1=特效(必填参数)
lua
reddot(actor, 104, 7, 15, 15, 1, 5055)

reddel(actor, win_id, btn_id)

给按钮删除红点,状态复位时清掉红点,漏清是红点系统最常见的坑

参数类型说明
actorobject玩家对象(必填参数)
win_idinteger窗口ID(必填参数)
btn_idinteger按钮ID/任务栏填任务ID(必填参数)

面板与按钮

openwindows(actor, winID)

查看自己面板,打开面板时再拉一次数据,而不是提前缓存

参数类型说明
actorobject玩家对象(必填参数)
winIDinteger101=装备 102=状态 103=属性 104=技能 105=生肖 106=称号 1011=时装(必填参数)

addbutton(actor, windowid, buttonid, icon)

增加自定义按钮,动态列表类界面靠它挂载

参数类型说明
actorobject玩家对象(必填参数)
windowidinteger主窗口ID(必填参数)
buttonidinteger按钮ID(必填参数)
iconstring图标内容(必填参数)

delbutton(actor, windowid, buttonid)

删除自定义按钮,界面关闭或数据缩短时必须回收

参数类型说明
actorobject玩家对象(必填参数)
windowidstring主窗口ID(必填参数)
buttonidinteger按钮ID(必填参数)

变量推送

sendredvartoclient(actor)

立即推送前端变量,需要即时刷新的显示项走推送,避免整面板重建

参数类型说明
actorobject玩家对象(必填参数)
作者履历与出处
本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理,讲解体系出自多年商业端开发生产一线。作者团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。
© 威海旷世互娱 · 返回文章地图 · 课程体系 · 幂尔框架