GAS(Gameplay Ability System)官方示例看完依然写不出项目代码,原因通常是把它当"技能插件"理解——实际上它是一个以属性账本为中心的游戏状态管理框架,技能只是账本的一种变更来源。这篇先建概念模型:五个核心类各管什么、为什么边界这么切。源码基于 UE5.3 的 Plugins/Runtime/GameplayAbilities。
一张图看清分工
| 类 | 角色 | 管什么 | 不管什么 |
|---|---|---|---|
UAbilitySystemComponent |
大脑 | 所有交互的入口:应用 GE、激活技能、查属性、管 tag | 具体属性怎么算 |
UAttributeSet |
账本 | 属性的 Base/Current 值存储与变更钩子 | 为什么变、谁来变 |
UGameplayEffect |
变更机制 | 一份"属性修改指令":改什么、改多少、多久 | 何时该发指令 |
UGameplayAbility |
逻辑 | 技能流程:激活条件、表现编排、结束时机 | 数值结果 |
UGameplayCue |
表现 | 特效/音效的触发与停止 | 任何逻辑 |
这个分层的驱动力只有一个:预测与复制。多人游戏要求客户端能乐观执行、服务器能权威裁决、两端能收敛。要做到这点,"游戏状态怎么变"必须是数据驱动的(可复制、可重放、可对比),不能散落在技能蓝图的流程图里。GE 作为数据化的变更指令,就是这套收敛机制的载体——技能逻辑随便写(不可复制),但它产生的效果必须落成 GE(可复制),分歧时以服务器的 GE 列表为准。
逐层展开
ASC:是 ActorComponent,挂在任何 Actor 上(角色、AI、甚至可交互道具)。它是唯一对外的门:外部代码不直接改属性,而是调 ASC->ApplyGameplayEffectToSelf(...);不直接调技能函数,而是 ASC->TryActivateAbility(...)。这个"单入口"设计让 ASC 能在每个入口挂统一的逻辑:预测窗口(FScopedPredictionKey)、tag 检查、网络复制标记。预测篇展开过 PredictionKey 机制,那一整套能 work 的前提就是所有副作用都过 ASC 这一个门。
AttributeSet:普通 UCLASS,里面是一组 FGameplayAttributeData 字段(UPROPERTY 标记,走反射),如 Health、Mana。注意它没有任何计算逻辑——BaseValue 和 CurrentValue 的推导全在外面的聚合器里(7020 篇)。AttributeSet 只提供存储和四个钩子:PreAttributeChange(改前夹取)、PostGameplayEffectExecute(改后响应,扣血到零触发死亡就挂这里)。属性定义直接写在 C++ 子类里而非数据资产,是为了反射驱动的序列化和网络复制的类型安全。
GameplayEffect:数据资产,一条 GE 描述一个完整的属性变更事务:target 属性、修改方式(Add/Multiply/Divide/Override)、量级(固定值或按技能等级缩放)、持续策略(Instant/Duration/Infinite)、应用条件(required/blocked tags)。GE 不是 UObject 的运行时实例——运行时实例是 FActiveGameplayEffect,存在 ASC 的一个容器里,GE 资产本身只读共享。这个"指令即数据"的设计是 GAS 复用性的根源:策划在数据资产里配一万个 buff,不碰代码。
GameplayAbility:逻辑载体,但不持有任何"结果"。它决定"什么时候可以激活"(CanActivate:tag 和冷却/消耗检查)和"激活后做什么流程"(ActivateAbility:播动画、发 GE、起 AbilityTask)。技能代码里凡是产生状态变化的地方,最终都要落成"应用某个 GE"或"加某个 tag"——这两样是唯二能被网络对账的原语。写 GAS 技能自检就一条:把 ActivateAbility 里的 GE 调用全删了,如果技能还有"实际效果",那效果就是不可预测的 bug 源。
GameplayCue:纯表现事件,带参数(位置、强度、tag)。它的定位是"GE/Ability 不想关心的视听细节":火球命中要爆什么粒子,逻辑层不配知道,只发一个 GameplayCue.Hit.Fire。Cue 有独立的复制通道和预测触发路径(7040 篇讲过去重),表现层和逻辑层解耦后,换特效不用动技能代码。
Tag:贯穿所有层的标签系统
FGameplayTag 在这套模型里是横向的胶水:GE 的应用条件靠 tag("眩晕中不能施法"= GE 给 ASC 加 State.Debuff.Stun,技能的 BlockedTags 里配这个 tag),技能的冷却和消耗靠 tag 检查,Cue 的路由靠 tag。Tag 把"状态"从"数值"里剥离出来独立流转——数值回答"还剩多少血",tag 回答"现在是什么状态",两者都过 ASC 统一入口,都能复制和预测。7050 篇单独拆 tag 的底层结构。
概念模型全景
上手顺序建议:先 AttributeSet(定义属性)→ 再 GE(配几个 buff 资产)→ 再 Ability(写第一个技能)→ 最后接预测和网络。反过来从网络开始调 GAS 是痛苦的常见路径。