유튜브 Unreal Engine KR 채널에 Gameplay Ability System(GAS) 강의 영상이 올라와서 이를 보고 공부한 내용을 정리해보려고 한다.
첨부된 사진 모두 유튜브 영상에서 캡처한 사진들이다.
https://www.youtube.com/watch?v=R2pbT0h3YZU&list=PLkHDai4yit5Wsu7mY-LM4GRprJOsV_IKo&index=2
Gameplay Ability System 개요
- 어빌리티의 소유 및 활성화 기능을 제공, 어빌리티/액터 간 상호작용을 지원하는 프레임워크
- RPG, 액션 어드벤처, MOBA 등 현대 게임 개발에서 폭넓게 활용되는 시스템
- 복잡한 멀티플레이어 게임 개발에도 안정적으로 대응 가능한 프레임워크
전통적인 게임 로직 모델
- FSM이나 Behavior Tree는 현재 상황에 맞춰 다음 행동을 결정하는 대표적인 의사결정 시스템
- 결정에 따른 행동 실행은 있으나, 결과를 시스템에 반영하는 피드백 구조는 부족
- 이러한 피드백 루프 시스템을 설계하려면 정교한 설계 능력과 깊은 개발 경험이 필요함

GAS로 완성하는 시스템 루프
- 의사결정에 따른 행동 결과가 다시 시스템에 피드백되어야 하나의 완전한 시스템 루프가 완성
- GAS는 시스템 루프 구현에 필요한 모든 요소를 제공하기에, 개발 경험이 부족해도 안정적인 시스템 제작 가능
- 숙련된 개발자의 노하우로 설계되어, 게임플레이 시스템 개발 입문자에게 훌륭한 길잡이가 됨

GAS의 장단점
장점
- 유연성과 확장성: 복잡하고 다양한 게임 개발 환경을 지원하도록 설계
- 모듈식 구조: 의존성을 최소화해, 각 기능이 독립적으로 작동하도록 구성
- 멀티플레이어 환경에 최적화: 네트워크 게임 환경에서 안정적으로 동작하도록 제작됨
- 데이터 기반 설계: 데이터 테이블과 환경 설정을 기반으로 동작하는 시스탬
- 상용 게임에서 검증된 시스템: 'Fortnite'와 같은 성공적인 프로젝트에서 그 성능이 입증됨
단점
- 높은 학습 난이도: 구성 요소가 많고 복잡하여 처음 배우는 데 시간이 오래 걸림
- 잠재적인 오버헤드: 규모가 작거나 단순한 프로젝트에 적용하기에는 시스템이 너무 복잡
GAS의 핵심 구성 요소

Ability System Component(ASC)
GAS를 구동하는 핵심 컴포넌트이다.
Actor에 ASC를 붙이면 해당 Actor는 GAS를 사용할 수 있다.
Gameplay Tag
Unreal에서 기본적으로 제공하는 Tag보다 강력한 계층구조를 지원하는 시스템이다.
Actor의 상태를 효과적으로 표현할 수 있어서 복잡한 코딩없이 특정 조건을 만족하면 스킬을 발동시키는 것이 가능하다.
Gameplay Ability(GA)
게임플레이 설계의 시작이다.
캐릭터가 행하는 모든 행동이나 스킬은 GA로 생성 가능하다.
GA로 포장된 캐릭터의 스킬은 성공, 실패, 취소 등 여러 결과를 가질 수 있는데, 이를 발동하는 것을 Ability Task로 처리한다.
이러한 스킬을 성공적으로 수행했다면 Gameplay Event를 통해 더욱 다양한 상황을 설계할 수 있다.
Attribute Set
체력, 스태미너, 임시 데미지 등 캐릭터가 가진 스탯을 표현하는데 사용한다.
Gameplay Effect(GE)
게임의 상호작용은 데이터 관점에서 발동한 캐릭터의 행동이 목표물에 적중하면 적중한 목표물이 가진 스탯을 변경하는 작업으로 요약할 수 있다.
예를 들어, 플레이어 공격은 공격이라는 어빌리티가 NPC에 적중하면 NPC의 체력 Attribute가 감소한다.
이때, 플레이어의 공격력에 따라 NPC의 체력을 얼마나 감소시켜야 할지 지정해야 하는데, 이러한 체계를 설계하는 것이 GE이다.
단순히 데미지를 주는 것만이 아닌, 지속 피해, 체력 회복, 중첩 버프, 무적 상태 등 복잡한 효과까지 제작 가능하다.
Gameplay Cue(GC)
캐릭터의 스킬이 발동할 때, 사용자에게 시각적, 청각적 피드백 효과를 주는 것이 중요하다.
GC는 이를 효과적으로 처리할 수 있도록 게임 클라이언트에서 사용되는 시각적, 청각적 효과를 모두 모아서 관리한다.
GAS로 만드는 핵심 게임플레이 루프

Ability System Component(ASC) 개요
- Ability System Component(이하 ASC)는 GAS 전체를 관리하는 핵심 컴포넌트
- 게임플레이 어빌리티와 관련 연산을 처리하는 CPU 같은 역할을 수행
- 하나의 액터에는 하나의 ASC만 부착 가능
- 액터에 ASC가 부착되어 있어야 게임플레이 어빌리틸를 활성화할 수 있음
- ASC가 부착된 액터 사이에서 GAS를 이용한 상호작용이 가능
Ability System Component 사용하기
- 액터는 부착된 ASC를 통해 게임플레이 어빌리티를 활성화할 수 있음
- GAS 시스템을 사용하는 액터 간의 상호작용은 양쪽 모두 ASC가 부착되어 있을 때 가능

Ability System Component 초기화
ASC는 AbilityActorInfo 다양한 정보를 저장하며, 이 정보는 시스템의 동작을 제어하는 데 사용.
AbilityActorInfo의 핵심 요소
- Owner(소유자): 어빌리티 시스템을 소유하는 액터
- Avatar(아바타): 어빌리티를 실제로 수행하는 물리적 액터
- 기타: PlayerController, ASC, SkeletalMesh, AnimInstance, MovementComponent 등

두 가지 형태로 모두 설정 가능하다.
기본적으로 Owner와 Avatar는 소유 액터 자신에게 할당되지만, C++에서 InitActorInfo 함수를 호출하여 변경 가능하다.
Gameplay Ability(GA) 개요
- 캐릭터가 다양한 행동 명령을 내릴 수 있게 함
- 공격, 마법, 필살기와 같은 개별 능력을 정의
- 복잡한 조건에 따라 여러 능력을 연계하여 실행 가능
- 주로 플레이어의 직접적인 입력을 통해 발동되도록 설계
- 혹은 특정 이벤트에 의해 조건이 만족하면 자동으로 발동되도록 설계
- 애니메이션 재생, 이동 제어, 스켈레탈 메시 설정 등 모션과 관련된 명령 처리에 특화
GAS에서 Ability 부여하기
- 하나의 게임플레이 어빌리티는 고유하고 독립된 클래스로 구성됨
- 어빌리티를 활성화하려면, 먼저 해당 어빌리티를 ASC에 부여(Give)해야 함
- 이 과정은
GiveAbility함수를 호출하여 구현
- 부여된 어빌리티는
SpecHandle 통해 제어
- 어빌리티가 활성화되면, ASC의 AbilityActorInfo가 전달되어 다양한 명령을 수행하는 데 사용

지연(Latent) 게임플레이 어빌리티
- 대부분의 캐릭터가 가진 어빌리티는 애니메이션 동작과 연결되어 일정 시간이 소요되는 형태
- 게임플레이 어빌리티가 성공적으로 시작되면 ActivateAbility 이벤트가 발동
- 게임플레이 어빌리티가 완료되면 반드시 EndAbility를 호출하여 정상적으로 종료해야 함

Activation Owned Tags는 자동 적용 및 제거한다.
Ability Tasks
- 어빌리티 실행 중 수행되는 작고 독립적인 작업
- 애니메이션, 타이머 등 특정 작업의 완료를 기다리는 기능을 주로 담당하는데, 이를은 지연 시간(latency)을 고려하여 설계됨
- 에픽게임즈에서 다양한 사전 제작된 Ability Tasks를 제공
- 블루프린트에서 여러 Ability Tasks를 조합하여 복잡한 게임플레이 어빌리티를 제작할 수 있음

Target Actor
- Target Actor: 어빌리티 타겟팅을 보조하기 위해 스폰되는 액터
어빌리티 태스크에 의해 생성되어 태스크 간에 전달된 타겟팅 데이터를 생성하고 결정함
- 언리얼에서는 다양한 내장 TargetActor를 제공하지만, 게임에 맞게 만들기 위해서는 C++을 사용해 구현해야 함
- 타겟팅 방식에는 크게 Instant(즉시)와 UserConfirm(사용자 확인) 두 가지가 있음
- Instant: 즉시 타겟을 확정하는 방식
- UserConfirm: 플레이어 입력을 통해 최종 타겟을 확정하는 방식
- ReticleActor: UserConfirm 방식에서 타겟 확인을 위해 사용되는 시각적 보조 액터
Ability Task와 Target Actor간의 실행 흐름
- Instant 또는 UserConfirm 타겟팅 방식에 따라 동작 방식이 달라짐
- 타겟 확정 시 마지막으로 ConfirmTargetingAndContinue가 호출됨
- 타겟이 확정되면 타겟 데이터(FGameplayAbilityTargetData)가 어빌리티 태스크로 전달됨
- 타겟 데이터는 HitResult 또는 타겟 액터 배열을 담고 있음

Gameplay Tag 개요
- 특성을 표현하기 위해
FNAME으로 관리되는 데이터 구조
- 액터나 컴포넌트에서 사용하는 언리얼 엔진의 태그와는 다름
- 프로젝트 설정에서 게임플레이 태그를 전역으로 관리하며, 프로젝트 전반에 사용함
- 게임플레이 태그는
DefaultGameplayTags.ini 파일에 저장하되, 다른 파일로도 확장 가능
- 계층적이고 모듈화된 구조 덕분에 체계적인 관리를 수행할 수 있음
- Gameplay Tags 예시
Actor.Action.Attack: 액션 애샛을 위한 태그로, 어빌리티를 발동시키는 데 사용
Actor.State.Attacking: 상태를 나타내는 태그로, 어빌리티의 활성화 상태를 감지하는데 사용
Event.Character.HitCheck: 캐릭터의 어빌리티가 적중했을 때 발동하는 이벤트 태그

Gameplay Tag Container 사용하기
- 여러 개의 게임플레이 태그를 담는 컨테이너
- GAS에서는 하나의 어빌리티에 여러 개의 게임플레이 태그를 할당하는 상황이 잦음
- 다양한 공격 타입에 따른 태그의 조합 예시:


Attribute Set 개요
- 다수의 GameplayAbilityData를 묶어 관리하는 언리얼 오브젝트
- 하나의 스탯에 대해서 Max 값을 별도로 GameplayAbilityData로 추가 설정하는 것을 권장
- 예) Health 스탯을 구축하기 위해 MaxHealth 스탯을 별도로 설정
- 보유한 스탯의 BaseValue가 변경되면 AttributeSet의 이벤트 함수가 호출
- PreAttributeChange
- 값이 변경 되기 전에 들어온 값의 처리
- 적용하기 전에 들어온 값의 변경이 가능
- 스탯 값을 안정적으로 유지시키는데 유용하게 사용 가능
- 권장하는 Health 스탯의 사전 설정 예시
- 현재 스탯이 최댓값 스탯값을 벗어나지 않도록 조율
- 최댓값 스탯이 최소 1이 되도록 조율 (HP바를 표시할 때 편리)
- PostAttributeChange
- BaseVaule가 변경된 후의 값 처리
- 처리가 끝난 이전 값(OldValue)와 신규값(NewValue)를 알려줌
- UI에서 변화를 감지하는데 유용하게 사용할 수 있음
AttributeSet 클래스는 현재 5.6 버전 C++로만 제작 가능하다.
GameplayAttributeData
- 캐릭터의 스탯 데이터를 관리하는 구조체
- 일반 float으로 값을 관리하기 보다 이 구조체를 사용해 관리하는 것을 강력 권장
- 하나의 스탯, 두개의 값: BaseValue & CurrentValue
- BaseVaule: 스탯이 가지는 확정적인 기본 값
- CurrentValue: 외부 효과(버프) 등에 의해 변화된 임시 설정값
- CurrentValue로 변화된 스탯 값은 언젠가 BaseValue로 돌아오다는 기획으로 설계
- 스탯에 관련된 주요 작업
- 스탯의 현재 값: GetCurrentValue 사용 권장
- 스탯에 설정할 값: SetBaseValue 사용 권장
- 스탯의 초기화: BaseValue와 CurrentValue를 같은 값으로 설정
- ASC는 InitializeComponent 함수에서 액터에 설정된 모든 AttributeSet 객체를 자동으로 찾아서 등록
- 이 작업이 끝나면 Actor의 PostInitializeComponents 함수가 실행
- 이때, 확정된 AttributeSet 정보를 UI에 보내 UI 이벤트 함수를 등록하는 것이 권장됨
- 이렇게 설정했다면 이후 발생하는 Attribute 데이터의 변화를 모두 UI에 자동으로 반영할 수 있음

- 다양한 상황에 유연하게 대응할 수 있도록 정의된 임시 Attribute
- 고정된 영구 데이터로 사용되는 것이 아닌 1회성 임시로 사용되도록 구현
- 대표적인 예시
- Health: 캐릭터의 현재 상태를 수치화한 스탯
- Damage: Health를 감소시키기 위한 임시 스탯
- Damage 스탯의 기본 설정
- 공격이 명중 할 때마다 발동
- 명중할 때의 공격자와 피해자의 상황에 따라 다양하게 계산
- 계산이 적용된 최종 데미지로 Health를 감소시키는데 사용
- 감소 후 다시 0으로 초기화
- Damage 스탯의 추가 설정
- 상대방에 실드가 있으면 실드를 우선 감소
- 실드를 감소시키고 남은 데미지를 Health 감소에 적용
- 상대방이 무적인 경우 데미지 무효화
- 공격 타입 상성에 따른 공격력 재설정
Gameplay Effect 개요
- 게임플레이 어빌리티가 목표하는(Targeting) 액터의 Attribute를 효과를 정리한 데이터 애샛
- 액터의 Attribute에 영향을 미치는 다양한 기능을 모아 제공
- Gameplay Effect의 특징
- 블루프린트 에디터에서 모든 값을 제어하도록 설계
- 블루프린트 로직 없이 기본 값 설정으로 모든 것을 처리
- C++로도 제작은 가능하나 블루프린트 에디터에서 설정하는 것을 권장
즉시 효과가 적용되는 Instant 타입과 지정한 기간동안 발동하는 Durational 타입으로 구분한다.
Gameplay Effect의 발동 과정
- 게임플레이 이펙트는 다른 요소들과 독립적으로 동작하도록 설계
- 하나의 게임플레이 이펙트가 스스로 동작하도록 동작 관련된 다양한 정보를 받아 실행됨
- GameplayEffectSpec = 다양한 정보를 담은 데이터
- GameplayEffectSpec에 포함되는 정보들
- 이펙트를 발동한 게임플레이 어빌리티와 이를 수행한 ASC의 관련 액터 정보
- 발동할 게임플레이 이펙트 클래스 정보
- 게임플레이 이펙트가 발동했던 상황 정보
- 레벨 및 스택 카운트
- GameplayEffectSpec 기반으로 자신에게 발동 혹은 다른 액터에게 발동 가능
- 자신: 레벨업을 통한 자신의 능력치 향상
- 상대방: 공격을 통한 상대방의 Health Attribute 차감

AttributeSet 연동
- AttributeSet에서는 Gameplay Effect 적용에 관련된 가상 함수를 제공
- PreGameplayEffectExcute
- Attribute가 변경 되기 전, 현재 진행 중인 Gameplay Effect를 진행할 것인지 확인하는 함수
- false를 반환함으로서 Gameplay Effect 진행의 취소 가능
- BaseValue 변경에 대해서만 반응함
- PostGameplayEffectExcute
- 게임플레이 이펙트가 확정되기 직전에 BaseValue를 수정할 수 있는 최종 함수
- 이후에는 추가 변경 불가능
- BaseValue 변경에 대해서만 반응함
- 최종 사용자 로직에 활용하면 좋음

Characteristics Of Durational Gameplay Effects
일반적인 Durational Gameplay Effect:
- BaseValue(기본값)가 아닌 CurrentValue(현재값)을 수정함
- 이펙트 지속 시간 동안만 임시로 변경되며, 종료 시 BaseVlaue로 자동 복구됨
- 지정한 조건을 만족할 때까지, 무한하게 지속하도록 설정하는 것도 가능
- Actor 타입 Gameplay Cue의 경우 GameNotifyCue가 발동됨.
주기가 정의된 지속성 게임플레이 이펙트는 매 주기마다 Instanct 게임플레이 이펙트처럼 작동함.

Gameplay Cue 개요
- 게임플레이 로직에 영향을 주지 않는 부가 효과(FX) 전용 기능
- Gameplay Effect: Attribute 변경 O (시스템 로직에 영향 O)
- Gameplay Cue: 시작적(VFX), 청각적(SFX) 효과만 담당 (시스템 로직에 영향 X)
- 효과 재생이 실패해도 게임 로직에 영향을 주지 않음 (Non-critical)
- 하나의 게임플레이 태그가 하나의 게임플레이 큐에 대응되는 구조
- 독립된 GameplayCue 관리자가 태그를 기반으로 FX 효과를 재생함

Gameplay Cue의 발동
Gameplay Cue의 발동
- GameplayCue로 시작하는 게임플레이 태그를 사용하여 발동 (내부 규칙)
- 자동 발동: 게임플레이 이펙트에 해당 게임플레이 큐 태그를 지정
- 수동 호출: 태그를 사용하여 원하는 타이밍에 직접 호출 가능
Gameplay Cue Tag와 애셋 규칙
- 자동 대응: 특정 폴더 내 블루프린트 이름이 게임플레이 큐 태그와 자동으로 매칭됨
- 예시) 블루프린트 이름 GC_DAMAGE_EFFECT -> GameplayCue.Damage.Effect 태그에 자동 대응
- 폴더 설정: 이 규칙이 적용될 게임플레이 큐 폴더는 프로젝트 세팅에서 지정 가능
Gameplay Cue 종류
Static vs Actor Cues
- Static: 일순간의 단발성 FX에 적합 (예: explosion, hit flash)
- Actor: 살아있는 동안 지속, 반복되는 FX에 적합 (예: looping aura effects)
GameplayEffect와의 연계
- Instant 타입 이펙트 -> GameplayCue Static이 적합 (예: 원샷 데미지)
- Daration 타입 이펙트 -> GameplayCue Actor가 적합 (예: 도트 데미지)
Event Functions
- GameplayCue Static: 발동 시 OnExecute 함수를 실행함
- GameplayCue Actor: 반복되는 주기마다 Executed 이벤트를 발생시킴

GAS의 Level-Up 시스템
- GAS의 어빌리티와 이펙트 모두 Level 파라미터를 포함 -> 유연한 스케일링 및 기능 확장에 용이
- 레벨별 값을 수동 입력하는 대신, 데이터 테이블이나 커브를 사용하여 전체 레벨 범위의 데이터를 효율적으로 설계하고 관리할 수 있음

GAS에서 캐릭터 레벨업 적용하기
레벨에 따른 캐릭터 스탯 초기화에는 다양한 방법이 있다.
Gameplay Effect 사용
- 레벨 기반 스탯 값을 부여하는 게임플레이 이펙트를 생성하여 캐릭터에 적용
- 세부 설정은 이펙트 애셋 내부에서 직접 구성
- 블루프린트 내에서 유연하게 처리 가능

글로벌 데이터 테이블 사용
- 프로젝트 세팅에 데이터 테이블을 등록하면 리플렉션을 통해 자동으로 적용함
- 이름이 GAS 명명 규칙을 따를 경우, 값이 자동으로 매핑됨
- 대규모 데이터 처리에 효율적
- C++을 통해서만 관리 가능
