中EN
概念页

Gameplay 能力系统

Gameplay Ability System

Gameplay 能力系统 (Gameplay Ability System, GAS) 是 UE 用来构建「Actor 可拥有并反复触发的能力」的框架:能力系统组件 (Ability System Component, ASC) 是持有者,Gameplay 能力 (Gameplay Ability) 编排执行过程,属性集 (Attribute Set) 存数值,Gameplay 效果 (Gameplay Effect, GE) 改数值和标签,Gameplay 标签 (Gameplay Tags) 做状态与互斥,Gameplay Cue 负责表现。它内建复制与客户端预测,代价是概念多、上手重,适合 RPG、动作、MOBA 这类技能密集型游戏。

为什么需要一个框架

官方把「能力」难做的原因归结为三点:要追踪所有者(计算时用谁的属性、得分记给谁)、追踪状态(已激活 / 进行中 / 已结束,Lyra 还追踪“已授予”)、协调执行(播蒙太奇、临时接管移动、特效、碰撞检测、改属性、扣资源、阻止其他能力、冷却、被打断、取消别的能力、响应中途输入、刷新 UI……)。单独写一次攻击很简单,但随着消耗、Buff、连招叠加,复杂度会爆炸。GAS 的做法是把每个能力建模为自己负责自己执行的独立实体。(Gameplay Ability System Overview)

注意:GAS 里的“所有者 (Owner)”和网络复制里的所有权 (Ownership) 不是一回事。(Gameplay Ability System Overview)

组件关系

下图概括各部件的从属与作用方向:ASC 挂在 Actor 上,持有能力、属性集、激活中的 GE、标签和 Cue;能力在执行中施加 GE,GE 改属性与标签并按标签触发 Cue。

flowchart LR
  Actor --> ASC["能力系统组件 ASC"]
  ASC --> GA["已授予的 Gameplay Ability"]
  ASC --> AS["Attribute Set 属性集"]
  ASC --> AGE["激活中的 GE 容器"]
  ASC --> Tags["拥有的 Gameplay Tags"]
  GA -- "施加" --> GE[Gameplay Effect / Spec]
  GE -- Modifier/Execution --> AS
  GE -- "授予/移除" --> Tags
  GE -- "匹配 GameplayCue.* 标签" --> Cue["Gameplay Cue 表现"]
  GA -- "启动" --> Task["Ability Task 异步任务"]

图中箭头表示“持有”或“作用于”。没有 ASC 的 Actor 无法使用能力;ASC 也是 Actor 在能力系统里的代表,提供属性、激活中效果、标签、Gameplay 事件的追踪接口。(Gameplay Ability System Overview)

部件职责关键约束
ASC (UAbilitySystemComponent)授予/移除/激活能力;多人下负责复制、向服务器转达操作、校验授权远程激活要求 ASC 的父 Actor 由本地控制的玩家拥有
Gameplay Ability (UGameplayAbility)编排一次能力的全部事件蓝图或 C++;主要工作交给 Ability Task,而非 Tick
Attribute Set (UAttributeSet)存放 FGameplayAttributeData 属性并监管修改只能用 C++ 创建;一个 ASC 可有多个属性集但类不能重复
Gameplay Effect改属性与标签是资产,运行时不可变;运行时操作的是 GE Spec
Gameplay Tags层级标签,状态/类别/事件必须注册到标签字典
Gameplay Cue音效/视觉反馈非可靠复制,只能做表现

(Gameplay Ability System Overview、Gameplay Ability、Gameplay Effects、Gameplay Attributes and Attribute Sets)

Gameplay Ability:授予、激活与结束

  • 授予:GiveAbility 以 FGameplayAbilitySpec 授予并返回 FGameplayAbilitySpecHandle;只有服务器能授予或撤销能力。撤销用 ClearAbility、SetRemoveAbilityOnEnd(执行完再移除)、ClearAllAbilities。(Gameplay Ability)
  • 生命周期:CanActivateAbility(只检查,可用于 UI 置灰)→ CallActivateAbility(不检查直接执行);常用的 TryActivateAbility = 检查 + 执行。重写 ActivateAbility 写主体逻辑;CommitAbility 实际扣除消耗并上冷却;CancelAbility 可被 CanBeCanceled 拒绝。(Gameplay Ability)
  • 必须调用 EndAbility:否则系统认为能力仍在运行,后续使用和被它阻挡的能力都会卡住。官方例子:“喝血瓶”没结束,角色就再也不能喝药、冲刺、爬梯子。这是最常见的坑。(Gameplay Ability)
  • 四种激活途径:Spec Handle 显式激活;Gameplay 事件(匹配 Ability Trigger,最适合把输入与决策抽象开);带匹配标签的 GE(如“睡眠”Debuff 触发倒地能力——受击反应也可以是能力);输入码 (Input Codes)。由事件触发时走 ActivateAbilityFromEvent,携带 FGameplayEventData,需单独处理这条路径。(Gameplay Ability System Overview、Gameplay Ability)

能力的互斥与条件靠标签表达,而不是手写 if:

标签变量作用
Cancel Abilities With Tag本能力执行时取消带这些标签的正在执行的能力
Block Abilities With Tag本能力执行时阻止带这些标签的能力执行
Activation Owned Tags执行期间给所有者加上这些标签
Activation Required / Blocked Tags激活者必须全有 / 不能有任一
Target Required / Blocked Tags目标必须全有 / 不能有任一

(Gameplay Ability)

实例化策略 (Instancing Policy):性能与功能的取舍

策略行为适用限制
Instanced per Execution每次执行新建对象低频能力,如 MOBA 大招(60–90 秒冷却、约 10 名角色)开销大;数百小兵的普攻会频繁创建(并可能复制)对象
Instanced per Actor每个 Actor 首次使用时建一个,之后复用需要复制变量/RPC 的能力,大规模战斗也表现好每次执行之间要手动清理成员变量
Non-Instanced不建对象,直接用 CDO高频、多人使用的能力,如 RTS/MOBA 普攻必须纯 C++;不能改成员变量、不能绑委托、不能复制变量或处理 RPC

另外,OnGiveAbility、CanActivateAbility 等回调可能在未激活时被调用:Per Actor 在实例上调用,另两种在 CDO 上调用。CDO 的概念见 UObject 与反射系统。(Gameplay Ability)

Ability Task:为什么不用 Tick

普通蓝图函数节点立即完成,而 Ability Task 会追踪自己处于未激活/进行中/完成,可在执行中触发事件,并感知父能力被取消以便清理。能力在激活时启动 Task,通过委托(C++)或输出执行引脚(蓝图)处理结果。项目通常会扩展自定义 Task 实现自己的玩法。这与 委托与 Tick 机制 中“能用事件就别用 Tick”的思路一致。(Gameplay Ability、Gameplay Ability System Overview)

Attribute 与 Attribute Set:基础值与当前值

每个属性同时保存基础值 (Base) 与当前值 (Current)。官方例子:跳跃高度基础值 100,“疲劳”效果为 70% → 当前值 70;升级后基础值 110 → 当前值 110×0.7=77110 \times 0.7 = 77。即时 (Instant) GE 修改基础值;有持续时间的 GE 修改当前值,效果结束即撤销。(Gameplay Attributes and Attribute Sets、Gameplay Ability System Overview)

实践要点(Gameplay Attributes and Attribute Sets、Gameplay Effects):

  • 用 GAMEPLAYATTRIBUTE_PROPERTY_GETTER / VALUE_GETTER / VALUE_SETTER / VALUE_INITTER 生成访问函数,是推荐做法;Actor 上以 const 指针持有属性集,防止代码绕过系统直接改。
  • 可用行类型为 AttributeMetaData 的数据表初始化,但表里的 MinValue/MaxValue 不生效——属性没有内建钳制,需自己做。
  • 钳制写在属性集里:PreAttributeChange / PreAttributeBaseChange 只负责约束取值、不应触发游戏反应;PostGameplayEffectExecute 负责最终钳制与反应(如血量归零死亡);自定义 Setter 应调用 SetNumericAttributeBase 改基础值,保证已有修饰器继续生效。
  • 多人下用 ReplicatedUsing + GAMEPLAYATTRIBUTE_REPNOTIFY + DOREPLIFETIME_CONDITION_NOTIFY(..., COND_None, REPNOTIFY_Always) 复制,机制见 网络复制与 RPC。

Gameplay Effect:资产 vs Spec

GE 是资产,运行时不可变;运行时实际传递的是 GE Spec(包在资产外的实例数据),蓝图库也以 Spec 为主。(Gameplay Effects)

持续类型是否进入激活容器术语
Instant否“Executed”
Has Duration / Infinite是(ASC 中的 Active Gameplay Effects Container)“Applied/Added”
周期性 (Periodic)是每周期既 Added 又 Executed

GE 的能力来自:Modifier(对属性做数学运算,例如护甲 +5% 基础值)、Execution(UGameplayEffectExecutionCalculation,处理 Modifier 写不清的复杂公式,可同时读施放者与目标)、Stacking(叠层上限、刷新/追加时长、独立计时)、以及 GE 组件 (GEComponent)——如授予目标标签、标签条件、免疫、概率施加、移除其他 GE 等。GEComponent 只能用 C++ 写,且所有已施加实例共享同一个组件对象。(Gameplay Effects)

Gameplay Tags

标签是用 . 分层的字符串,如 Character.Enemy.Zombie、Movement.Mode.Swimming,用法类似布尔/标志位,但可按层级匹配。必须先注册:项目设置(存为 Config/DefaultGameplayTags.ini 等,文本编辑后需重启编辑器)、数据表(行类型 GameplayTagTableRow)、或 C++ 宏 UE_DECLARE_GAMEPLAY_TAG_EXTERN / UE_DEFINE_GAMEPLAY_TAG(_COMMENT/_STATIC)(需在 Build.cs 加 GameplayTags 模块,见 模块、插件与构建系统)。容器 FGameplayTagContainer 提供 HasTag/HasAny/HasAll;注意空容器作为参数时只有 All 类函数返回 true。复杂条件用 FGameplayTagQuery。(Gameplay Tags)

Gameplay Cue:只做表现

Cue 是负责音效和视觉效果的 Actor/UObject,与标签关联(必须以 GameplayCue. 开头),匹配标签的 GE 会自动生成并运行它,从而可以建立一个“通用特效库”而不必在代码里手动触发;也可脱离 GE 直接触发(Lyra 的开火反馈)。Cue 不使用可靠复制,部分客户端可能收不到,因此只能用于表现;与玩法相关、必须送达的反馈应交给 Ability Task(如 Play Montage Task)。(Gameplay Ability System Overview、Gameplay Effects)

Cue 的处理类与事件(UE 5.8 API)

5.8 没有找到 Gameplay Cue 的概念文档页,下列内容来自 C++ API 参考。(Gameplay Cue API (UGameplayCueNotify_Static, UGameplayCueManager, UGameplayAbility))

  • UGameplayCueNotify_Static:不实例化的 UObject 处理器,适合一次性「爆发」特效;派生类有 UGameplayCueNotify_Burst、UGameplayCueNotify_HitImpact。持续型、需要状态的效果则由 UGameplayCueManager 按需生成 GameplayCueNotify Actor。
  • 事件:OnActive(带持续时间的 Cue 首次激活,只有客户端亲眼看到激活才调用)、WhileActive(首次看到处于激活状态,包括中途加入)、OnExecute(瞬时效果或周期 tick)、OnRemove(移除)。中途加入的客户端只会收到 WhileActive,所以持续表现应放在 WhileActive 而不是 OnActive。
  • 标签层级与覆盖:IsOverride 决定是否覆盖父标签的 Cue,例如 Damage.Physical.Slash 处理后不再调用 Damage.Physical,参见 Gameplay 标签深入。
  • 复制选择:UGameplayCueManager 是负责分发 Cue 的单例;官方注释说明动画总用非复制的 Cue(动画本就在模拟代理上执行),能力总用复制的 Cue(能力不在模拟代理上执行)。
  • 不经 GE 直接触发:能力里可用 K2_ExecuteGameplayCue(一次性)、K2_AddGameplayCue/K2_RemoveGameplayCue(持续,可随能力结束自动移除)。

网络:复制什么、预测什么

  • ASC 不会把能力和 GE 复制给所有客户端,只复制它们影响到的属性和标签——省带宽也防作弊。(Gameplay Ability System Overview)
  • Net Execution Policy 四选一:Local Predicted(本地立即执行,服务器拥有最终裁决,手感好)、Local Only、Server Initiated(准确但有延迟)、Server Only。(Gameplay Ability)
  • 预测被服务器拒绝时要回滚。多数非即时 GE 支持回滚,但伤害等即时属性/标签变化不支持。正是因为这种回滚能力,官方建议所有标签、Cue、属性变化都通过 GE 施加,而不是直接改。(Gameplay Ability System Overview)
  • 与服务器拥有的对象(NPC 等)交互时,要经由本地拥有的 Actor(通常是 Pawn)上的复制能力或其他服务器函数。所有权概念见 网络复制与 RPC 与 Gameplay 框架。(Gameplay Ability System Overview)

取舍与常见坑

问题说明
忘记 EndAbility能力永远“进行中”,阻塞后续能力
用 Cue 驱动玩法Cue 非可靠复制,会不同步
直接改属性/标签绕过 GE 就失去预测回滚
以为数据表 Min/Max 会钳制不生效,需在属性集里写
高频能力用 Per Execution大量对象创建与复制开销
在客户端授予能力只有服务器能授予/撤销

适用性上,官方定位是 RPG、动作冒险、MOBA 等能力需要协调机制、特效、动画、音效与数据驱动元素的游戏,也可改造用于更多项目;对只有少量简单交互的游戏,引入 GAS 的学习与搭建成本可能高于收益。(Gameplay Ability System Overview)输入如何触发能力可结合 增强输入;能力中播放蒙太奇见 动画蓝图与动画系统。

  1. Gameplay Ability System Overview UE 5.8 文档
  2. Gameplay Ability UE 5.8 文档
  3. Gameplay Effects UE 5.8 文档
  4. Gameplay Attributes and Attribute Sets UE 5.8 文档
  5. Gameplay Tags UE 5.8 文档
  6. Gameplay Cue API (UGameplayCueNotify_Static, UGameplayCueManager, UGameplayAbility) UE 5.8 API 参考(Cue 概念页未找到)

相关页面

游戏开发 · UE5UObject 与反射系统UObject & Reflection System虚幻引擎 (Unreal Engine) 的对象基类是 UObject。在 C++ 类、属性、函数上加 UCLASS/UPROPERTY/UFUNCTION 等宏,再由构建前的预处理工具虚幻头文件工具 (Unreal Header Tool, UHT) 扫描头文件生成代码,引擎就能在运行时“看见”这些类型——这就是反射系统 (Reflection System)。垃圾回收、序列化、编辑器面板、蓝图、网络复制都建立在它之上。游戏开发 · UE5Gameplay 框架Gameplay FrameworkGameplay 框架 (Gameplay Framework) 是 UE 提供的一组相互配合的类,用来搭建游戏的基本结构:Actor 与组件 (Component) 构成场景中的一切;GameMode 在服务器上定规则并生成玩家;玩家由“控制器 (Controller) + 棋子 (Pawn)”组成;GameState 与 PlayerState 负责把全局与每个玩家的状态复制给所有客户端;GameInstance 跨关卡存活。游戏开发 · UE5委托与 Tick 机制Delegates & TickUE 有两种驱动游戏逻辑的方式:事件驱动——委托 (Delegate) 在某事发生时回调绑定的函数;轮询驱动——Tick 每帧(或按最小间隔)调用 Actor/组件的更新函数,并按 Tick 组 (Tick Group) 与物理模拟排序。官方建议能用定时器、委托就不用 Tick,必须 Tick 时用 Tick 组和 Tick 依赖保证顺序,避免“差一帧”问题。游戏开发 · UE5网络复制与 RPCNetwork Replication & RPCUE 采用服务器权威 (Server-Authoritative) 的客户端-服务器模型:游戏真正在服务器上进行,服务器把状态复制 (Replication) 给客户端,客户端通过远程过程调用 (Remote Procedure Call, RPC) 向服务器请求操作。开发者需要显式声明哪些 Actor、属性、函数要走网络,并借助所有权、网络角色、相关性、优先级控制“发给谁、发多少”。UE 5.8 提供通用复制系统、Replication Graph 和实验性的 Iris 三套复制系统。游戏开发 · UE5增强输入Enhanced Input增强输入 (Enhanced Input) 是 UE5 默认启用的输入插件,把输入拆成四层:输入动作 (Input Action) 表示“玩家想做什么”,输入映射上下文 (Input Mapping Context) 规定“哪些按键在什么情境下触发它”,输入修饰器 (Input Modifier) 预处理原始值,输入触发器 (Input Trigger) 判定是否触发。上下文可在运行时按优先级增删,从而用数据资产而非代码处理情境切换、按键冲突与改键。游戏开发 · UE5动画蓝图与动画系统Animation Blueprint & Animation SystemUE5 角色动画以动画蓝图 (Animation Blueprint) 为核心:它每帧为骨骼网格体 (Skeletal Mesh) 计算最终姿势。动画蓝图内部用状态机 (State Machine) 组织“何时播什么”,用混合空间 (Blend Space) 按速度、方向等参数连续混合,用蒙太奇 (Animation Montage) 在插槽 (Slot) 中插播攻击、交互等一次性动作,用 Control Rig 做程序化骨骼控制(如贴地)。算出的骨骼姿势最终交给蒙皮 (Skinning) 驱动顶点。游戏开发 · UE5Gameplay 标签深入Gameplay Tags In DepthGameplay 标签 (Gameplay Tags) 是用 . 分层的用户定义标签,必须登记到标签字典(项目设置 .ini、数据表或 C++ 原生标签宏)。对象用 FGameplayTagContainer 持有多个标签并以 HasTag/HasAny/HasAll 判断(注意空集合语义),复杂条件用 FGameplayTagQuery 的叶/根表达式组合并配置在资产里。它是 GAS、AI 和各类玩法状态的通用词汇表;大项目可限制标签编辑权限,并用 IGameplayTagAssetInterface 免 Cast 取标签。游戏开发子类沙盒Subclass Sandbox子类沙盒 (Subclass Sandbox) 让基类提供一组受保护的“提供的操作”和一个抽象的沙盒方法,派生类只用这些操作来实现沙盒方法。这样大量派生类(例如几十种超能力)只耦合到基类,不直接接触引擎的各个系统;代价是基类会越来越臃肿,变成脆弱基类。游戏开发类型对象Type Object类型对象 (Type Object) 用“一个类的不同实例”来表示不同的逻辑类型:例如不为每种怪物写一个子类,而是一个 Monster 类加一个 Breed(种族)类,每个 Breed 实例描述一种怪物,怪物只持有指向自己 Breed 的引用。这样新增或修改种类只需要改数据,不必重新编译;代价是要自己管理这些类型对象,而且给每种类型定义不同的“行为”会变难。游戏策划常见类型的经济机制Common Genre MechanismsAdams & Dormans 第 6 章 "Example Mechanics" 用 Machinations 图逐一拆解各类型游戏的典型经济机制:动作游戏的道具与收集品、竞速游戏的橡皮筋、RPG 的经验与等级、FPS 的弹药与生命、RTS 的采集/建造/战斗与科技树。作者刻意把机制单独隔离建模——完整游戏的图很快变得复杂,而透彻理解每个组件是理解整体动态的第一步(尽管涌现型游戏的整体总是大于部分之和)。游戏策划内部经济Internal Economy内部经济 (Internal Economy) 是游戏中资源被生产、消耗、交换的系统——不只是金钱,生命、经验、技能、弹药、军队、"战略优势"都可以是资源。Adams & Dormans 第 4 章给出其基本元素(资源、实体、源/泄/转换器/交易器四种经济功能),说明机制结构如何产生可从图表看出的经济形状 (Economic Shapes)(负反馈→均衡,正反馈→军备竞赛/下行螺旋),并讨论内部经济在动作、进程、策略、可定制与经济建造类游戏中的用法。游戏开发 · UE5模块、插件与构建系统Modules, Plugins & Build SystemUE 的代码由模块 (Module) 组成:每个模块是一个独立编译单元,用 [模块名].Build.cs 声明依赖。插件 (Plugin) 是可按项目启用/禁用的代码与内容集合,用 .uplugin 描述,可包含多个模块。虚幻构建工具 (UnrealBuildTool, UBT) 根据 .Target.cs 和 .Build.cs(而不是 IDE 的 .sln)编译,默认把模块编成 DLL 由一个可执行文件加载,也可整体链接成单体 (Monolithic) 可执行文件。游戏开发享元模式Flyweight Pattern享元模式 (Flyweight Pattern) 把对象的数据拆成可共享的“内在状态”和每个实例独有的“外在状态”,让大量对象共用一份内在状态。森林里成千上万棵树共用一份网格和纹理,以及瓦片地图中每格只存一个指向共享地形对象的指针,都是它的典型应用。游戏开发命令模式Command Pattern命令模式 (Command Pattern) 把一次方法调用“物化”成对象,从而可以存储、传递、延迟执行、排队或撤销。游戏里最典型的三种用法是:可配置的按键映射、让玩家输入和 AI 共用同一套“驱动角色”的接口、以及撤销/重做。游戏开发对象池Object Pool对象池 (Object Pool) 预先一次性分配一组可复用对象,需要时从池里取一个未使用的对象并初始化,用完标记为未使用,而不是逐个 new/delete。它能避免频繁分配的开销和堆碎片,常用于粒子、子弹、正在播放的声音等。代价是池大小要调校、同时活跃的数量有上限、复用的对象不会被自动清零,在有 GC 的环境里还可能让本该回收的对象一直活着。综合游戏编程模式选型:解耦与性能Choosing Game Programming Patterns本页把《Game Programming Patterns》里的 19 个模式放到同一张取舍图上:大多数模式要么为了解耦(降低改代码时需要装进脑子里的知识量),要么为了性能(利用对数据和硬件的具体假设),而这两个目标经常互相拉扯。下面先讲全书的定位和 Nystrom 的架构观,再给出按问题选模式的路线和与 UE 的对照。

被这些页面引用1 篇

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原