Unreal - Tag与GameplayTag
目录
1. Actor Tags:基础但脆弱的“老兵”
Actor Tags 是定义在 AActor 类中的一个简单字符串数组:
TArray<FName> Tags;
特点:
- 实现简单:你可以直接在 Actor 的 Details 面板里手动输入任何字符串。
- 扁平化结构:它是完全平等的字符串列表,没有层级关系。
- 低门槛:不需要任何前置配置。
致命弱点:
- 拼写地狱(Typo-Prone):你在代码里检查
"Stunned",但策划在编辑器里手抖打成了"Stuned"。编译器不会报错,但你的逻辑会莫名其妙地失效。 - 缺乏逻辑关联:如果你想检查一个角色是否处于“任何负面状态”,你必须手动列出
"Stunned","Frozen","Burned"。你无法通过类似“所有的 Debuff”这样的母概念来查询。 - 性能瓶颈:在大规模查询时,字符串比较的效率远低于数值比较。
2. Gameplay Tags:结构化与高性能的“现代派”
Gameplay Tags 是随 GAS 系统一同发扬光大的高级标签系统。它不再是随手乱写的字符串,而是需要在项目设置中注册的规范化数据。
特点:
- 层级结构(Hierarchical):支持
A.B.C的格式。例如State.Debuff.Stun。 - 高性能:虽然我们在编辑器里看到的是文字,但其底层会被转换为唯一的 32位整数 ID。这意味着在执行“是否拥有该标签”的检查时,本质上是极快的整数比对。
- 强类型安全:你只能从预定义的列表中选择标签,彻底杜绝了拼写错误。
- 容器化(Container):配套的
FGameplayTagContainer支持强大的位运算,可以瞬间判断“包含全部”、“包含任意”或“不包含”。
3. 核心差异对决
| 特性 | Actor Tags (FName Tags) | Gameplay Tags |
|---|---|---|
| 底层数据 | FName (字符串) |
int32 (整数 ID) |
| 结构形态 | 扁平数组 (Flat) | 树状层级 (Hierarchical) |
| 容错率 | 极低 (拼写错误无提醒) | 极高 (IDE/编辑器自动补全) |
| 查询性能 | 一般 | 极快 |
| 逻辑深度 | 仅支持精确匹配 | 支持父子包含关系(匹配 A 即可匹配 A.B) |
| 管理方式 | 散落在各个 Actor 实例中 | 中心化管理 (Data Table 或 .ini) |
4. 为什么 GAS 选择了 Gameplay Tags?
GAS 的核心灵魂是 “基于状态的逻辑切换”。如果没有 Gameplay Tags,GAS 几乎无法工作。
A. 模糊匹配的威力
假设你的技能要求“目标不能处于任何 Debuff 状态”。
- 使用 Actor Tags:你需要检查目标是否不含标签 A、B、C…(如果以后新加了 D 状态,所有技能代码都要改)。
- 使用 Gameplay Tags:你只需要检查目标是否拥有
State.Debuff。无论子级是Stun还是新加的Sleep,只要它属于State.Debuff的子树,系统就能自动识别。
B. 数据驱动的解耦
Gameplay Tags 允许策划在不触碰 C++ 代码的情况下,通过修改 GE(Gameplay Effect)里的标签组合,直接改变技能的互斥、中止和叠加逻辑。
C. 网络同步优化
由于 Gameplay Tags 内部是整数,它在网络传输时的开销远小于发送长字符串,这对于高频同步的多人对战游戏至关重要。
5. 什么时候该用哪种?
-
使用 Actor Tags 的场景:
- 非常简单的原型开发。
- 非游戏逻辑的简单标记(例如:标识场景中哪些物体是“可抓取的”)。
- 由于历史原因残留的旧插件接口。
-
使用 Gameplay Tags 的场景(推荐):
- 所有的战斗系统、技能系统、状态系统。
- UI 数据的分类与筛选。
- 复杂的交互逻辑(如:只有手持
Item.Key.Blue的玩家才能打开Door.Blue)。
结语
如果说 Actor Tags 是路边随处可见的便利贴,那么 Gameplay Tags 就是图书馆里的索引系统。
对于追求严谨、性能和可扩展性的虚幻开发者来说,尽快抛弃 Actor Tags 并全面拥抱 Gameplay Tags,是迈向高级架构师的必经之路。
版权声明:本文为原创技术博客,转载请注明出处。