[UnrealOpenDay2020] 深入GAS架构设计 | EpicGames 大钊
[UnrealOpenDay2020] 深入GAS架构设计 | EpicGames 大钊
本期将深入 GAS 相关内容,涉及 GAS 内部类图关系、核心概念和结构等
传送门:[UnrealOpenDay2020]深入GAS架构设计 | EpicGames 大钊
一. GAS 基础
1.1 GAS 概述
- GAS:全称 Game Ability System 游戏技能系统
-
是 EPIC 从 Paragon 和 Fortnite 开始,为满足自己游戏项目开发和使用的游戏技能框架系统,之后不断迭代、优化,封装为内置插件以供使用
-
GAS 是在 UE 自身 GamePlay 之外的一套框架,可配合 GamePlay 框架和 AI 模块(行为树)一起使用
-
GAS 支持联机游戏中的网络复制和预测机制,服务器上的技能逻辑可以广播到客户端上展示,客户端技能也可以在本地先执行,若服务器预测不通过,则可以在客户端上回滚操作
![1.1-1GAS 概述]()
- GAS 的使用时机 :
| Strong(优势) | Weak(劣势) |
|---|---|
| 灵活易扩展,可实现复杂的技能流程 | 大量的概念和类,学习曲线陡峭 |
| 支持联机复制(属性复制、RPC广播)和动作预测回滚 | 重度 C++,对 BP 不够友好 |
| 解耦,易于团队协作和项目复用 | 需要按照框架定义一堆类才能开始启动 |
| 细粒度思考实现单个动作逻辑 | GAS 的网络服务必须配合 DS |
| 数据驱动、数值配置 | 实践演化框架,可选插件,文档不足 |
| 已帮你处理繁杂流程麻烦逻辑 | 要求技术功底高,源码 Debug 能力强 |
| 人多 - 大项目 - 多技能 - 联机 - 技术强 - 重表现 | 人少 - 小项目 - 少技能 - 单机 - 技术弱 - 弱表现 |
3. GAS 开发初衷是处理联机环境下的复杂技能逻辑
1.2 如何设计一个易于拓展的技能系统
抛开 GAS,设计一个易于拓展的技能系统,需要分析一个技能里包含哪些元素:
- 逻辑部分
-
技能的获得和释放
-
触发判断的条件
-
Buff 系统
- 视听部分
-
动作动画
-
特效
-
声效
- 数据部分
-
数值计算
-
数据配置
- 如何考虑网络联机同步?
-
设计模式的本质是抽象变化,因此解耦技能系统中可以变化的部分,独立变化
-
技能包含变化的部分较多,GAS 设计的概念和类也比较多,如:
-
UAbilitySystemComponent - ASC
-
UGameplayAbility - GA
-
UGameplayEffect - GE
-
UGameplayCueNotify - GC
-
FGameplayAttribute - Attribute
-
FGameplayTag - Tag
-
UGameplayTask - Task
-
FGameplayEventData - Event
-
1.3 GAS 核心概念
-
UAbilitySystemComponent(ASC):能力系统组件(技能系统组件),缩写 ASC,只有拥有 ASC 的 Actor 才拥有管理释放技能的能力,ASC 也负责管理其他的技能部分
-
UGameplayAbility(GA):技能逻辑,定义一个技能的主体逻辑
-
UGameplayEffect(GE):游戏效果,这个效果一般是进行属性修改或动作效果触发
-
UGameplayCueNotify(GC):游戏特效,包含一次性特效(如:爆炸)、持续性特效(如:持续燃烧)
-
FGameplayAttribute(Attribute):游戏属性,描述生命值、攻击力、防御力等,多个 Attribute 组成 AttributeSet,挂在 Actor 上
-
FGameplayTag(Tag):游戏标签,是广泛使用且功能强大的标签系统,通过给类和对象挂上标签,就可以层次化地判断和搜索各个条件
-
UGameplayTask(Task):GAS 中异步操作的节点(如:在技能中播放蒙太奇,需要等蒙太奇结束后再结束技能,此时就需要异步操作)
-
FGameplayEventData(Event):ASC之间可以通过游戏事件来通知对方
1.4 一个技能的自我修养
-
Who:谁能放技能?AbilitySystemComponent
-
How:技能的逻辑?GameplayAbility
-
Change:技能的效果?GameplayEffect
-
What:技能改变的属性?GamePlayAttribute
-
If:技能涉及的条件?GameplayTag
-
Visual:技能的视效?GameplayCue
-
Async:技能的长时行动(异步)?GameplayTask
-
Send:技能消息事件?GamePlayEvent
二. GAS 核心结构
-
蓝色的 GameplayTag 和 GameplayTask 都是独立的模块,其本身可以脱离 GAS 存在,可被单独引用,也可以单独学习分析(初学 GAS 可以从这里开始,代码量较少,可以快速对 GAS 基础设施有概念)
-
GameplayTag 和 GameplayTask 都被 GameplayAbility.uplugin 核心插件引用(AI 模块也引用了 GameplayTag 和 GameplayTask)
-
同时,绿色的 Editor 模块引用了蓝色的 Runtime 模块,Editor 模块主要是实现编辑 UI,提供了在编辑器里遍历的编辑方式

2.1 GameplayTag 游戏标签
-
层次化的字符串标签(通过
.符号,区分父子级) -
轻量 FName,可附加到各类上(如:GameplayEffect、GameplayAbility、GameplayCue、GameplayEventData)做搜索条件
-
整体所有 Tag 构成一颗 Tag 树,存放在 UGameplayTagsManager 下,方便快速查找

组合Tag,灵活的逻辑查询 Tags:
-
多个 Tag 被组合起来构成一个 FGameplayTagContainer
-
也可以被组合在一起,加上逻辑操作符作为一个 TagQuery
-
一个 Tag 和一个 GameplayTagNode (树节点)相关联

2.2 GamePlayAttribute 游戏属性
-
float BaseValue:基础值,非最大值,永久值
-
float CurrentValue:当前值,Buff 叠加后的值,临时值
-
数据配置上,可从 DataTable 或 CurveTable 中读取值,AttributeSet 可定义多个/多套属性值

2.3 GameplayEffect 技能效果
-
决定一个技能的“逻辑效果”
-
纯配置蓝图,不需要重载函数
-
GameplayEffect(GE)是修改 Attribute 的唯一合法通道,所有 Attribute 改动必须经此流程,以便让 GE 完整跟踪修改过程,触发对应事件回调,实现对属性变更的统一管控,禁止任何手动直接修改 Attribute 的操作
-
GE 配置功能包括:类型、修改器、周期、应用需求、溢出处理、过期处理、显示处理、Tags 条件、免疫、堆叠、能力赋予...

-
UGameplayEffect 只是作为一个数据模版,“Spec”才是每次 Apply 后生成的实例
-
UGameplayEffect 由 FGameplayModifierInfo(属性栏修改器)和 FGameplayEffectCue (GE 触发的 Cue 行为)组成
-
在 GameplayAbility 调用 Apply 时,GameplayEffect 生效,每次调用 Apply 都会产生一个 FGameplayEffectSpec(GE 的实例)
-
FGameplayEffectSpec 自带等级,等级决定不同技能属性值,每个 Spec 对应一个 Active 实例,最终通过组合,存储到 ASC 里面
-
简言之:模板(UGameplayEffect)→实例化(Apply 出 Spec )→组合存储(进 ASC )
-


2.4 GameplayCue 技能特效
-
决定一个技能的“视觉效果”
-
可全局配置 Tag-Handler 的映射(Tag 和继承自 UGameplayCueNotity 特效播放器的一一对应)
-
可通过 Effect 触发,也可 GA 手动触发
-
Cue分为:Static 一次性、Actor 持久
-
可在 Cue 的重载函数里编写蓝图节点,触发粒子特效/音效,常见重载,如:OnActive、WhileActive、Executed、Removed

-
Cue 可在 GE 中配置触发,或在 GA 里调用 Execute/Add 触发,触发后生成的实例存储在 FGameplayCueObjectLibrary 对象库,以提供后续复用,减少触发时延迟
-
Cue 的触发分为:
-
Static Cue:直接在 CDO 上调用(不要在 Cue 里保存状态,不会生成新对象)
-
Actor Cue:触发 Spawn,生成新实例
-
-
生效的 Cue 最终在 ASC 里面引用保存

2.5 GameplayAbility 游戏技能
-
“技能”是很广义的抽象
-
基础移动、射线检测、UI 交互,不是技能,GAS 中的技能用于表示专门触发某一件事情,而不是平时一直在做的事
-
在不同的 Actor 上学习、取消、释放不同技能,构成了主体逻辑
-
写主体逻辑的地方
-
可重载函数及回调:ActiveAbility 激活、CommitAbility 提交、CancelAbility 取消、EndAbility 结束

-
UGameplayAbility 可用 CDO 模板,也可生成实例保存状态
-
Spec 是技能学习后,带等级的“实例”
-
UGameplayAbility可以通过调用 TryActiveAbility,在外部被 OwnerActor 触发
-
自身不需要保存状态的 UGameplayAbility,可用 CDO 模板直接调用,若是需要每次实例化都跟踪不同状态,可选择每次生成新 Spec 实例(带等级,等级传递给 GE 触发对应技能属性值),激活后的 GA 保存在 ASC
-


2.6 GameplayTask 游戏异步任务
-
执行异步任务的框架
-
Task 框架本身是比较基础的模块,可在 GAS 外被单独使用,只需添加 GameplayTaskComponent
-
可用于异步长时动画的触发和等待
-
已经预实现好了一系列常用 Tasks
-
可重载:Activate、TickTask

-
UAbilityTask 继承自 UGameplayTask,并实现了一系列 Task
-
UAbilityTask 相较父类,多了 GA 引用
-
这些 Task 都在 ASC 中执行(ASC 是继承于 Task 组件的)
-

2.7 GameplayEvent 游戏事件
-
手动触发游戏类型
-
不同事件靠 Tag 识别,可携带 Payload 数据
-
可触发技能
-
在另一端可等待具体 Tag 事件触发

-
GA 在 WaitGameplayEvent 时,向 ASC 注册回调,通过 Tag 映射识别
-
外部其他 GA 调用 SendGameplayEvent 时,使用 EventTag 在 ASC 映射表中检索,检索成功后触发回调

2.8 AbilitySystemComponent 游戏技能组件
-
ASC 是技能系统运行的核心,负责管理协调其他部件:Ability、Effect、 Attribute、 Task、 Event...这些交互都在 ASC 里做记录和转发
-
只有拥有 ASC 的 Actor 才拥有释放技能的能力
-
ASC 放在 Pawn 还是 PlayerState 上,这是个问题
-
联机游戏,推荐放在 PlayerState 上,会复制到各个端且会一直存在(Pawn 重生后可能会丢失状态)
-
单机游戏/简单项目,放在 Pawn 上也可以
-

-
技能互相作用:其实就是一个 Actor 上的 ASC 作用到另一个 Actor 上的 ASC,其互相增删 Effect、触发 Cue、互相给对方贴标签等
-
ASC 继承自 UGameplayTaskComponent,有执行 Task 的能力,同时还实现了多个接口
-
ASC 挂在 OwnerActor 上,初始化时,寻找 OwnerActor 上的 AttributeSet 注册起来
-
ASC 是技能框架运行的核心,GAS 提供的功能,大部分接口可以在 ASC 头文件中找到
-

三. 小结
-
Actor 之间通过 ASC 来相互交互
-
ASC 最重要的类是 GameplayAbility
-
GA 可以给对方 ApplyEffect,也可以 Add/Execute Cue 播放特效。而 Effect 的生效又可以修改 AttributeSet 中的属性,或赋予新的 GA
-
GA 在执行时,发起 Task 进行异步操作,或给对方 Actor 的 ASC 手动 Event 事件通知
-



浙公网安备 33010602011771号