lua-游戏红点提示系统抽象设计

news/2025/2/25 23:14:18

文章目录

  • 前言
  • 一、定义红点节点类型
  • 二、节点注册与管理
    • 三、状态更新与冒泡机制
  • 四、示例配置与使用
  • 五、结构示意图
  • 六、关键机制说明
  • 总结


前言

游戏开发中,红点提示系统可以通过树形结构和策略模式进行抽象,实现高扩展性。以下是基于Lua的实现方案:


一、定义红点节点类型

节点分为两种类型:

  • 叶子节点:直接绑定条件函数(如检查新道具)
  • 组合节点:自动聚合子节点状态(任一子节点激活则激活)
lua">-- ========================
-- 红点系统核心管理器
-- ========================
local RedPointManager = {
    -- 所有注册的红点节点,以节点ID为键
    nodes = {},       
    
    -- 没有父节点的根节点集合(例如HUD入口)
    rootNodes = {},   
    
    -- 事件监听器(扩展功能:事件触发自动更新)
    eventListeners = {} 
}

-- ========================
-- 节点评估策略模块
-- ========================
-- 叶子节点评估方法:直接执行条件函数
local function evaluateLeaf(node)
    -- 当且仅当条件函数返回true时激活
    return node.condition and node.condition()
end

-- 组合节点评估方法:检查任意子节点是否激活
local function evaluateComposite(node)
    for _, child in ipairs(node.children) do
        if child.isActive then
            return true -- 任一子节点激活则组合节点激活
        end
    end
    return false
end

二、节点注册与管理

lua">-- ========================
-- 节点注册与管理模块
-- ========================
--- 注册一个红点节点
--- @param nodeId string 唯一节点标识(例如"WeaponTab")
--- @param parentNodeId string|nil 父节点ID(nil表示根节点)
--- @param nodeType "leaf"|"composite" 节点类型
--- @param condition function|nil 仅叶子节点需要的条件函数
function RedPointManager:RegisterNode(nodeId, parentNodeId, nodeType, condition)
    -- 创建节点数据结构
    local node = {
        id = nodeId,             -- 节点唯一标识
        parent = parentNodeId and self.nodes[parentNodeId], -- 父节点引用
        children = {},            -- 子节点列表(仅组合节点使用)
        isActive = false,         -- 当前激活状态
        evaluation = nodeType == "leaf" and evaluateLeaf or evaluateComposite, -- 评估策略
        condition = condition,    -- 条件函数(仅叶子节点)
        uiCallback = nil          -- UI刷新回调
    }
    
    -- 构建父子节点关系
    if node.parent then
        -- 将当前节点添加到父节点的子节点列表
        table.insert(node.parent.children, node)
    else
        -- 没有父节点时加入根节点列表
        table.insert(self.rootNodes, node)
    end
    
    -- 将节点注册到全局管理器
    self.nodes[nodeId] = node
    return node
end

--- 为指定节点注册UI刷新回调
--- @param nodeId string 目标节点ID
--- @param callback function 回调函数(参数:isActive)
function RedPointManager:RegisterUICallback(nodeId, callback)
    local node = self.nodes[nodeId]
    if node then
        node.uiCallback = callback -- 绑定UI更新逻辑
    end
end

三、状态更新与冒泡机制

lua">-- ========================
-- 状态更新模块
-- ========================
--- 标记某个节点需要重新评估状态
--- @param nodeId string 需要更新的节点ID
function RedPointManager:MarkDirty(nodeId)
    local node = self.nodes[nodeId]
    if node then
        self:_EvaluateNode(node) -- 立即触发评估
    end
end

-- 内部方法:递归评估节点状态
function RedPointManager:_EvaluateNode(node)
    -- 执行节点对应的评估策略(叶子节点/组合节点)
    local newActive = node.evaluation(node)
    
    -- 仅当状态变化时触发后续操作
    if newActive ~= node.isActive then
        node.isActive = newActive -- 更新节点状态
        
        -- 执行UI刷新回调(通知前端更新红点显示)
        if node.uiCallback then
            node.uiCallback(node.isActive)
        end
        
        -- 冒泡机制:状态变化时向上更新父节点
        if node.parent then
            self:_EvaluateNode(node.parent) -- 递归评估父节点
        end
    end
end

四、示例配置与使用

lua">-- ========================
-- 示例用法模块
-- ========================
-- 初始化红点树结构
RedPointManager:RegisterNode("HUDEntry", nil, "composite") -- 根节点
RedPointManager:RegisterNode("PropPanel", "HUDEntry", "composite") -- 二级节点
RedPointManager:RegisterNode("WeaponTab", "PropPanel", "leaf", function()
    -- 叶子节点的具体条件判断:玩家是否有新武器
    return Player.HasNewWeapons()
end)

-- 绑定UI元素的红点显示逻辑
RedPointManager:RegisterUICallback("HUDEntry", function(isActive)
    -- 当HUD入口红点状态变化时,调用HUD系统接口
    HudView.SetRedDot("MainEntry", isActive)
end)

RedPointManager:RegisterUICallback("WeaponTab", function(isActive)
    -- 武器标签红点状态变化时,更新道具界面
    PropView.SetWeaponTabRedDot(isActive)
end)

-- ========================
-- 业务逻辑触发示例
-- ========================
-- 当玩家获得新武器时
function Player.OnNewWeaponAdded()
    -- 直接标记叶子节点需要重新评估
    RedPointManager:MarkDirty("WeaponTab")
end

-- ========================
-- 扩展功能:事件驱动更新
-- ========================
--- 注册事件监听(例如:道具变化、邮件到达等)
--- @param eventType string 事件类型
--- @param nodeId string 关联的节点ID
function RedPointManager:AddEventListener(eventType, nodeId)
    self.eventListeners[eventType] = self.eventListeners[eventType] or {}
    table.insert(self.eventListeners[eventType], nodeId)
end

-- 全局游戏事件处理器
function OnGameEvent(eventType, ...)
    local nodes = RedPointManager.eventListeners[eventType]
    if nodes then
        for _, nodeId in ipairs(nodes) do
            RedPointManager:MarkDirty(nodeId) -- 自动触发相关节点更新
        end
    end
end

-- 示例:将武器标签与新武器事件绑定
RedPointManager:AddEventListener("NEW_WEAPON", "WeaponTab")

五、结构示意图

lua">HUDEntry(组合节点)
├─ PropPanel(组合节点)
│  ├─ WeaponTab(叶子节点,条件=有新武器)
│  └─ ArmorTab(叶子节点,条件=有新防具)
└─ MailPanel(组合节点)
   └─ SystemMail(叶子节点,条件=未读邮件)

该设计通过分层抽象,实现以下优势:

  1. 低耦合:界面层仅关注回调,逻辑层管理状态
  2. 易扩展:新增红点只需注册节点+条件
  3. 高效更新:事件驱动+冒泡机制减少无效计算
  4. 灵活策略:支持自定义条件与聚合逻辑

六、关键机制说明

  1. 树形结构管理
    • 根节点(如HUD入口)→组合节点(如道具面板)→叶子节点(如武器标签)
    • 父节点状态自动由子节点决定,无需手动维护
  2. 状态更新流程
lua">graph TD
A[玩家获得新武器] --> B(标记WeaponTab为脏)
B --> C{评估WeaponTab状态}
C -->|状态变化| D[更新武器标签UI]
D --> E{存在父节点?}
E -->|是| F[递归评估PropPanel]
F --> G{状态变化?}
G -->|是| H[更新道具面板父节点]
H --> I[继续冒泡到HUDEntry]

总结

该设计通过清晰的层级划分和事件驱动机制,使红点系统具备:
✅ 新增功能只需添加节点+条件
✅ 状态变更自动传播
✅ 界面与逻辑完全解耦
✅ 支持复杂嵌套规则(如:主界面红点=任务红点 OR 邮件红点)


http://www.niftyadmin.cn/n/5866956.html

相关文章

DPVS-5: 后端服务监控原理与测试

后端监控原理 被动监测 DPVS自带了被动监控,通过监控后端服务对外部请求的响应情况,判断服务器是否可用。 DPVS的被动监测,并不能获取后端服务器的详细情况,仅仅通过丢包/拒绝情况来发觉后端服务是否可用。 TCP session state…

nuxt实现原理

Nuxt.js 是一个基于 Vue.js 的框架,旨在简化和增强 Vue 应用的开发。Nuxt 主要用于构建服务端渲染(SSR)和静态生成的 Vue 应用,它自动处理了一些 Vue 应用的常见问题,如路由配置、服务器端渲染等。下面是 Nuxt.js 的实…

Go语言--语法基础2--下载安装

2、下载安装 1、下载源码包: go1.18.4.linux-amd64.tar.gz。 官方地址:https://golang.google.cn/dl/ 云盘地址:链接: https://pan.baidu.com/s/1N2jrRHaPibvmmNFep3VYag 提 取码: zkc3 2、将下载的源码包解压…

数据库面试题(基础常考!!!)

在数据库领域,无论是日常开发还是面试场景,都有一些高频且重要的问题需要我们深入理解和掌握。本文将对这些常见面试题进行详细阐述,帮助大家更好地应对面试和实际工作中的挑战。 面试题一:三范式详解 什么是三范式 三范式是关…

QT 引入Quazip和Zlib源码工程到项目中,无需编译成库,跨平台,加密压缩,带有压缩进度

前言 最近在做项目时遇到一个需求,需要将升级的文件压缩成zip,再进行传输; 通过网络调研,有许多方式可以实现,例如QT私有模块的ZipReader、QZipWriter;或者第三方库zlib或者libzip或者quazip等&#xff1…

【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案

在CentOS环境下搭建并使用log4cplus这一高效、灵活的日志记录组件,对于提升应用程序的日志管理能力至关重要。本指南将分步骤介绍如何安装log4cplus,并提供针对可能遇到的常见错误的解决方案,确保您能够顺利集成并应用这一强大工具。 安装前…

touchgfx的工作机制

touchgfx的工作机制 一.MVP软件架构 MVP的全称为Model-View-Presenter Model: 就是数据部分,在整个touchgfx应用中,只有一个Model类实例对象,它为所有的Screen屏幕界面服务,可以理解成是一个全局变量区,同时它还负责和后端系统通信 View: 就是UI界面部分,对应于View类,在整…

电脑没声音了怎么恢复正常?一键恢复电脑声音

电脑是我们日常生活和工作中必不可少的工具之一,而其中的声音功能更是我们使用电脑时经常会用到的。然而,有时候我们可能会遇到电脑没有声音的情况,这给我们的使用带来了很大的困扰。那么当电脑出现没有声音的情况时,我们该如何恢…