UE5 C++ 数据驱动玩法架构:用 World Subsystem 与 Data Asset 拆分平台逻辑

引言
你是否曾经发布过一个 Game Jam 原型,然后意识到它无法扩展?这就是我们在 Meowsic 上遇到的情况。
在 GMTK Game Jam 2025 期间,我们做了一款节奏解谜游戏,你扮演一只待在数字音频工作站(DAW)里的猫。这就是 Meowsic。一款打破类型边界的节奏平台跳跃游戏,平台就是你的音频循环。四天,一个关卡,成功发布。社区很喜欢它。但后来我们决定把它做成一款完整的 Steam 商业游戏,包含 2-5+ 个关卡和数十种平台变体。就在那时,我们在 Game Jam 时期的架构崩掉了。
我们最初的方法很简单:一个个单独的平台 Actor,手动配置,由一个中央协调器管理。对 Game Jam 原型来说,它运行得很完美。但当我们计划制作多个关卡并加入平台变体时,迭代变得慢得令人痛苦。设计师没法做实验。我花了大量时间管理一致性,而不是开发功能。改动一个平台属性,就意味着要更新 40+ 个 Actor。
我需要一种根本不同的方法:把数据和行为分离,让配置改动能立刻波及所有实例,并且降低而不是放大制作阻力。
解决方案就是 Layered Gameplay Systems Model(分层玩法系统模型),一种架构模式,它把任何玩法系统拆解为五个不同的层,每一层都有明确职责。它并不只适用于平台或 Meowsic。任何包含数据、规则和多个实例的系统都能从这种方法中受益。
问题:为什么它会崩掉
一致性问题
想象 40 个平台 Actor 分布在 7 种变体上。每个都带有移动行为、音频、材质、网格类型等属性。你发现最大 Z 高度错了,本应是 800,却设成了 500。你更新了一个 Actor,测试了一下,感觉不错。
但另外 6 个呢?你更新它们了吗?你怎么知道它们是一致的?在手动工作流里,你并不知道。你要么更新每一个 Actor(繁琐且容易出错),要么指望自己全都抓到了(馊主意),要么制造出破坏玩家预期的视觉不一致(更糟)。

迭代问题
设计师想做实验。“如果平台移动得更高呢?如果被踩到时变色呢?如果音频以不同音高播放呢?”
每次实验都意味着:
- 在 PlatformActor 中新建一个属性;
- 在测试关卡里放置 7 个平台副本;
- 逐个配置每一个;
- 测试行为;
- 如果不行,就删掉全部 7 个,从头再来。
一个迭代循环要花 30+ 分钟。设计师不再做实验了。迭代速度崩塌了。

性能与重复问题
每个平台在内存中都是一个完整的 AActor。对于 2-5 个关卡、每关 50 个平台来说,就是 100-250+ 个实例。每个实例都携带相同的属性和逻辑,相同的移动速度、音频提示和规则被存储了 250 次。
关卡加载时间攀升到 5-10 秒。而且我们有大量代码重复,灵活性却很低。核心问题是:配置和行为被紧紧耦合在一起。每一次改动都意味着要改很多地方。
解决方案:把数据与行为分离
核心洞察
如果我们把架构反过来呢?
而不是:
Actor [配置 + 行为]… × 250
我们可以改成:
DataAsset [配置]
↓ 引用
Actor [仅行为]… × 250
现在全部 250 个 Actor 都引用同一份配置。改一次数据,每个 Actor 都会立即更新。没有重复。没有不一致。没有琐碎的重复劳动。

Layered Gameplay Systems Model(分层玩法系统模型)
为了干净地实现这一点,我总结出了一套模式:五个不同的层,每一层都有明确职责。

第 1 层:表示——配置存在哪里?
答案:UPlatformDataDefinition(自定义 DataAsset)。唯一事实来源,可复用,可热加载。
第 2 层:转换——我们如何将存储的数据转换为运行时值?
答案:PlatformSubsystem 读取 DataAsset 并计算运行时特定的值。它会限制范围、执行计算,并组合属性。
第 3 层:验证——平台遵循哪些规则?
答案:子系统强制执行约束。最小/最大位置、基于视图的操作以及碰撞检查。
第 4 层:编排——谁管理一切?
答案:PlatformSubsystem 是唯一权威。它跟踪实例、应用逻辑、执行规则、响应事件,并保持一切同步。
第 5 层:接口——设计师如何交互?
答案:蓝图函数库(Platform API)。设计师调用简洁的函数,无需理解子系统或验证逻辑。
每一层都是独立的。更改一层而不会破坏其他层。信息向上流动;编排向下流动。
实现
这种方法的美妙之处在于简单。
Platform Actor 变成一个薄封装:就是这样。该 Actor 引用一个 DataDefinition,向子系统注册,并从子系统接收状态。不再有跨 250 个实例重复的属性。没有配置逻辑。只是一个薄封装。
Platform Data Definition 定义并管理数据在 Data Assets 中的表示方式。



PlatformSubsystem 成为核心:
- 跟踪所有平台实例;
- 根据 DataAssets 计算 Platform 状态;
- 验证交互;
- 读取 DataAsset 并计算运行时特定的数值;
- 响应玩法事件;
- 保持所有内容同步。



PlatformLibrary 暴露以下 API:
- “获取所有平台”;
- “获取可移动平台”;
- “设置平台数据”;
- “注册平台”。
设计师可以在蓝图中使用这些函数,而无需接触 C++。


结果
主平台类从 300 多行减少到仅 100 多行,代码量减少了 67%。此前重复的平台特定逻辑被集中到了单一系统中。
向数据驱动工作流的转变也对生产效率产生了重大影响。此前需要 30 多分钟的任务,例如在整个项目中更新平台属性,现在只需 2-3 分钟即可完成。创建一个新的平台类型过去需要 20 多分钟,现在只需 3-5 分钟。此前需要 1-2 小时调试的一致性问题的已通过自动化消除。此外,关卡加载时间大幅改善,从 5-10 秒降至约半秒。
设计师体验
之前:“如果平台再高一些会怎样?”——45 分钟的设置——“还是别试了”
之后:“如果平台再高一些会怎样?”——创建 Gameplay Tag、链接到 Platform Data Struct、配置、测试——“我们试 10 个变体,挑出最好的”
迭代速度改变了。创造力提升了。这才是真正的胜利。
何时使用此模式
此模式适用于任何具有以下特征的玩法系统:
- 数据(控制行为的配置);
- 规则(验证和约束);
- 实例(同一事物的多个副本)。
示例:
- 战利品掉落:跨数千个实例的掉落率、稀有度、数量;
- 敌人类型:每关 50+ 种敌人的属性、AI 行为、平衡规则;
- 对话树:跨数百个节点的分支逻辑;
- 音频系统:跨数千个声源的参数与提示。
问问自己:我是否有 10 个以上实例共享同一份配置?迭代是否缓慢?一致性 Bug 是否常见?如果其中 3 个以上回答是“是”,就采用这种模式。
结语
最好的架构不是抽象最多的那个,而是能消除意图与执行之间摩擦的那个。
当设计师想“我想让平台再升高 4 格”,并且能在 10 分钟内完成而不是花 2 小时,某些根本性的东西就变了。他们不再受实现细节的束缚,可以自由创作。
这种自由会不断累积。迭代叠加迭代,实验带来发现,发现带来只有你的团队才能做出的独特玩法。
对 Meowsic 来说,这套架构帮我找到了数据中的乐趣,并且一直持续找到新的乐趣。
从一个最痛的系统开始小步推进。按照这五个层级构建一个子系统。衡量结果。看到有效后再扩展。这个模式可以从一个系统扩展到几十个系统。回报不只是更整洁的代码或更快的迭代,而是能够无所畏惧地实验,不断尝试各种变体,直到找到那个神奇的东西。这值得为之付出。
Chukwuyenum Opone,游戏玩法程序员
相关链接
原文链接:https://80.lv/articles/building-scaleable-data-driven-gameplay-architecture-in-ue5-using-c
喜欢这篇内容吗?