Skip to content
写作:2026-05-11更新:2026-05-16字数:—阅读:—维护:Azek431

创游世界广播驱动项目架构实战

一句话摘要

广播是创游世界项目解耦的核心手段,但滥用广播会导致事件来源不清、维护困难。本文从实战角度讲解广播的分类方法、命名规范、作用域设计,以及常见反模式与正确做法。

适合谁阅读

  • 已经理解广播基础概念,想在实际项目中正确使用广播的制作者
  • 项目逐渐复杂,开始出现“广播满天飞”问题的开发者
  • 想学习如何用广播配合组件、变量、UI 构建可维护架构的学习者

你将学到什么

  • 广播的三层分类方法
  • 广播的命名规范与约定
  • 如何用广播配合数据层分离
  • 广播的常见反模式与正确做法
  • 完整的项目架构示例

核心结论

  1. 广播应该按用途分类,而不是按功能堆叠
  2. 广播名称应该包含事件语义和目标层级
  3. 广播不适合替代数据持久化
  4. 广播应该是单向事件流,不是双向通信
  5. 大量同层级广播应考虑合并或升级为中间层

背景说明

在创游世界中,广播是跨对象通信的主要手段。它允许一个对象触发事件,其他对象监听到并响应,而不需要直接引用对方。

但在实际项目中,很多人会陷入两个极端:

  • 要么完全不用广播,所有逻辑都写在一起
  • 要么滥用广播,每个小动作都发广播,导致事件来源不清、调试困难

正确的做法是理解广播的本质:它是事件通知机制,不是数据存储机制,也不是逻辑执行机制。

基础概念

什么是广播

广播是一种消息发布-订阅机制:

  • 发布者通过「发送广播」指令发出一个消息
  • 订阅者通过「当收到广播」触发器监听消息
  • 收到消息后,订阅者执行对应逻辑

广播 vs 其他通信方式

通信方式适用场景不适用场景
广播解耦、跨对象事件通知、UI刷新触发需要返回值、需要确认处理结果
直接调用组件方法同对象内的逻辑调用跨对象业务逻辑
变量读写数据共享、状态持久化事件通知

广播的三个层级

按作用范围,广播可分为:

  1. 对象内广播:在同一对象内部使用广播解耦逻辑
  2. 地图内广播:在同一地图内跨对象通信
  3. 全局广播:跨地图通信,通常用于存档、云变量同步

广播分类方法

推荐的三层分类

第一类:状态变更广播

描述:对象状态发生变更,通知相关方刷新

命名规范:状态_对象_变更类型

示例:

  • 道具_获得_玩家
  • 生命_减少_怪物
  • 金币_增加_玩家

第二类:UI刷新广播

描述:数据层变化后,通知UI层刷新显示

命名规范:UI_刷新_目标

示例:

  • UI_刷新_背包格子
  • UI_刷新_血条
  • UI_刷新_商店列表

第三类:业务事件广播

描述:游戏业务逻辑中的重要事件,用于触发后续处理

命名规范:事件_业务_描述

示例:

  • 事件_任务完成_玩家
  • 事件_商店购买_完成
  • 事件_战斗结束_结算

广播名称示例

markdown
✅ 正确示例:
- 道具_获得_玩家
- UI_刷新_背包格子
- 事件_任务完成_玩家

❌ 不推荐示例:
- 刷新(太泛)
- 更新(语义不清)
- 通知(没有目标)

项目架构示例

最小可用的广播架构

假设我们要做一个背包系统:

玩家对象
├── 属性:背包数据(JSON格式存储物品ID和数量)
├── 脚本A:当获得物品时执行
│   ├── 解析物品ID和数量
│   ├── 更新背包数据
│   ├── 发送广播「道具_获得_玩家」(带参数:物品ID、数量)
│   └── 发送广播「UI_刷新_背包格子」
├── 脚本B:当收到「UI_刷新_背包格子」时执行
│   ├── 读取背包数据
│   ├── 遍历并渲染格子UI
│   └── 绑定格子点击事件
└── 脚本C:当收到「道具_获得_玩家」时执行
    └── 显示获得物品的浮动提示

这个架构的特点:

  1. 数据层(背包数据)和显示层(UI格子)分离
  2. 广播用于通知状态变更,不承担数据传递职责
  3. 每个脚本职责单一,容易维护

进阶架构:多层中间层

当项目变大时,可以引入中间层:

全局管理器对象
├── 脚本A:管理所有「事件_」类广播
│   ├── 维护全局状态
│   ├── 处理跨对象业务逻辑
│   └── 发出「状态_」类广播
└── 脚本B:管理所有「UI_」类广播
    ├── 监听状态变更
    └── 统一刷新相关UI

这样做的好处:

  1. 业务逻辑集中在管理器
  2. 对象脚本只负责监听和执行
  3. 方便后续扩展和调试

常见反模式与正确做法

反模式1:广播内嵌业务逻辑

markdown
❌ 反模式:
当获得道具时:
  发送广播「获得道具」,参数:物品ID
当收到「获得道具」时:
  如果参数.物品ID == 1:
    金币加100
    显示提示
  如果参数.物品ID == 2:
    生命加50
    显示提示

这种写法把业务逻辑分散在多个监听点,难以维护。

markdown
✅ 正确做法:
当获得道具时:
  道具ID = 参数.物品ID
  更新背包数据(道具ID、数量)
  发送广播「数据_背包_更新」,参数:道具ID、数量
  发送广播「UI_刷新_背包格子」

当收到「数据_背包_更新」时:
  调用「处理道具逻辑」,参数:道具ID、数量

反模式2:广播嵌套广播

markdown
❌ 反模式:
当收到广播A时:
  发送广播B
当收到广播B时:
  发送广播C
当收到广播C时:
  执行实际逻辑

广播嵌套会导致事件链路不清晰,难以追踪数据流向。

markdown
✅ 正确做法:
当获得道具时:
  更新数据
  发送广播「数据_更新」(一次广播,携带完整数据)
当收到「数据_更新」时:
  刷新UI(如果需要)
  显示提示(如果需要)

反模式3:用广播替代数据存储

markdown
❌ 反模式:
当获得道具时:
  发送广播「道具数据」,参数:道具ID、数量
当收到「道具数据」时:
  显示道具(但不存储)

广播是事件通知,不是数据存储。数据应该存储在变量或组件属性中。

markdown
✅ 正确做法:
当获得道具时:
  更新背包变量(数据存储)
  发送广播「数据_更新」(通知相关方)

广播命名规范总结

类型命名格式示例
状态变更实体_状态_操作道具_获得_玩家生命_减少_怪物
UI刷新UI_刷新_目标UI_刷新_背包格子UI_刷新_血条
业务事件事件_业务_描述事件_任务完成_玩家事件_战斗结束_结算
系统广播系统_功能_操作系统_存档_保存系统_初始化_完成

广播使用检查清单

在发送广播之前,检查以下问题:

  • [ ] 这个广播是否描述了一个真实的事件?
  • [ ] 广播名称是否能让人一眼看出含义?
  • [ ] 是否有其他对象会监听这个广播?
  • [ ] 这个广播是否需要参数?参数是否必要?
  • [ ] 是否可以用变量替代这个广播?
  • [ ] 是否在用广播替代数据存储?

相关页面

待验证问题

  • [待验证] 在复杂项目中,广播的性能开销是否有明显影响?
  • [待验证] 是否有广播数量的合理上限建议?

后续优化方向

  • 可以补充具体项目的完整广播链路图
  • 可以补充调试广播的常用方法
  • 可以补充广播与事件系统的对比分析

参与维护

发现文档问题?

你可以编辑页面、提交反馈,或复制链接给维护者,帮助这个资料库继续变好。

由 Azek431 整理与维护 | 基于 MIT 许可证开源