인프런 : https://www.inflearn.com/course/%EC%9D%B4%EB%93%9D%EC%9A%B0-%EC%96%B8%EB%A6%AC%EC%96%BC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-part-4/dashboard
Udemy : https://www.udemy.com/course/unreal-engine-5-gas-top-down-rpg/
추가 문서 : https://kkadalg.tistory.com/29
command list
- showdebug abilitysystem
- PageUp/Down으로 ASC를 가진 객체들을 순환할 수 있음
-> DefaultGame.ini에서 [/Script/GameplayAbilities/AbilitySystemGlobals] bUseDebugTargetFromHud=True로 해줘야 AI도 보임
1. ASC ( AbilitySystemComponent )
- Actor에 interface 설정 : public IAbilitySystemInterface
- ASC . InitAbilityActorInfo( 실 소유자, 시각효과 발현자 ) ( possessed시(server), onrep_playerstate시(client) )
-> 실 소유자의 owner는 항상 playercontroller야 함 ( playerstate owner는 항상 controller, pawn은 possess시 controller )
- ASC . TryActivateAbility, CancelAbilityHandle ( FGameplayAbilitySpec* . Handle )
- 접근 - UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent( 소유 액터 )
- 외부에서는 GetGameplayAttributeValueChangeDelegate() 같은걸로 attribute change noti delegate를 구독할 수있음
- SetReplicationMode Minimal AI용, Mixed 플레이어용, Full 싱글플레이어용
Use Case
GE
Tag, Cue
Full
Single
o
o
Mixed
Multi, PlayerControlled
owner-only
o
Minimal
Multi, AI-Controlled
x
o
2. GA ( GamePlayAbility )
- 액션단위
- ASC에선 FGameplayAbilitySpec* 으로 액션에 대한 instance를 제어 ( . handle을 통해 asc에서 내부 function에 접근 )
- FGameplayAbilitySpec* .. = ASC . FindAbilitySpecFromClass ( {GamePlayAction.child}::StaticClass() ) 로 생성
- InstancingPolicty ( * 꼭 설정해줄것. default가 InstancedPerExecution )
- NonInstanced : 인스턴싱 없이 CDO에서 일괄 처리, 단순, 상태부여는 어렵
- InstancedPerActor : 액터마다 인스턴스. 고유스테이트 - 일반적
- InstancedPerExecution : 어빌리티 발동시마다 인스턴스 발동. 액션마다 스테이트
- 폰들 ( ASC의 owner 및 avatar )에 대해선 각 메서드 super에서 parameter로 받는 ActorInfo 내에 owner, avatar를 통해 접근 가능
- GA를 상속받은 BP에서 각 State ( override )에서의 GameplayTag를 정의할 수 있음
3. GameplayTag
- #include "GameplayTagContainer.h"
- DefaultGameplayTags.ini에 생성 및 관리
- 계층구조를 가지는 태그 ( ex Actor . Action . Rotate )
- 쿼리검색 -> HasTagExact, HasAny, HasAnyExact, HasAll, HasAllExact 등
- Gameplay Ability System에서 사전정의된 태그리스트가 있음
- AbilityTags 태그컨테이너
- CancelAbilitiesWithTag 태그 컨테이너 등 ( BlockAbilitiesWithTag, ActivationOwnedTags, ActivationRequiredTags ... )
- 파라미터로 사용할 Tag의 포인터는 FGameplayTag::RequestGameplayTag(FName("태그이름")) 으로 얻음
( FGameplayTagContainer 타입 )
4. 기본 Architecture
- GA에 AbilityTags.AddTag로 어빌리티 태그 할당, ActivationOwnedTags로 상태태그 추가
- ASC -> GiveAbility를 통해 ASC에 해당 GA 추가
( FGameplayAbilitySpec ..(GA)를 GiveAbility에 박음. FGASpec이 GA 매니저인듯 )
- ASC -> TryActivateAbilititesByTag나 CancelAbilities 를 통해 Tag로 GA 트리거
5. GASpec ( Gameplay Ability Spec )
- ASC에서 GA를 관리할때 사용하는 중간매개체 ( 정확히는 GASpec의 Handle을 통해 관리 )
- 추가적인 메타데이터, 설정값을 포함
- GA의 상태 등에 대해 가져올 수 있음
- Handle값은 전역이며, 스펙생성시 1씩증가 ( 기본값 -1 )
- GA의 instance에 in32 InputID를 할당하고 ASC에서 ID를통해 접근할 수 있음 ( FindAbilitySpecFromInputID )
-> GA가 발동중이면 입력신호전달 ( AbilitySpecInputPressed, 아니라면 발동 TryActivateAbility 하는 등 )
-> 입력 release시 AbilitySpecInputReleased
6. AT ( Ability Task )
- NewAbilityTask < child class > ( owner GA ) 로 생성
- GA는 1frame내 동기처리가 기본
- animation과 타이밍 등 비동기적 요소가 포함된 스펙을 AT에서 관리
- UAbilityTask_PlayMontageAndWait 등
- 해당 태스크의 static 변수로 이닛 ( ex. CreatePlayMontageAndWaitProxy )
- OnComplated 등에 AddDynamic으로 콜백함수 연결하고 ( GA의 ActivateAbility 메서드 시점에서 AT의 델리게이트를 GA 콜백함수에 연결 )
- FreadyForActivation();으로 실행개시
- 필요시 콜백함수에서 GA의 EndAbility ( GA종료 ) 호출
- MontageJumpToSection 등 내장된 편의기능이 많음 ( GA )
- 시작 : Activate ( override ) , 종료 : OnDestroy ( override )
- static method에서 NewAbilityTask < AT class(보통자신) > ( GA ) 넣어서 해당 ga용 특정 at 생성 가능
- 얘넨 그냥 GetAvatarActor 가지고있네 내장함수로
예제에서는 EnhancedInputSystem에서 IA에 Callback함수를 binding할 때, 같은 Callback을 바인딩하고 input param에 GA의 Id를 줘서 하나의 callback 함수로 여러 input(IA) -> action(GA)을 바인딩하고있음
7. GE ( Gameplay Event )
- ( Anim Notify등에서 ) Actor(보통 캐릭터)의 가상함수에
FGameplayEventData PayloadData;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(OwnerActor, TriggerGameplayTag, PayloadData);
를 보낼 수 있음. TriggerGameplayTag는 블프나 notify detail에서 할당해도되고, 코드에 직접박아도 되고
그리고 액터의 ASC에 GA를 바인딩한 다음, GA의 AbilityTriggers ( TArray<FAbilityTriggerData>)에 해당 TriggerGameplayTag를 등록
- 등록은 걍 BP에서 하는게 편함
8. TA ( GameplayAbilityTargetActor )
- StartTagetting -> ConfirmTargeting(AndContinue), CancelTargeting 등
- 타켓 판정 및 관리 ( line trace, collision trace 등 )
- Target Data Handle에서 Target Data들을 묶어서 전달
- SpawnActorDeffered로 지연생성하고, 델리게이트 구독 등 초기화 별도로 해줌 ( AT에서 )
-> FinishSpawning -> StartTargetting(in Ability) -> ConfirmTargeting
- Start에서 SourceActor에 타격판정할 액터 등록 // #If Enable Draw Debug
9. Attribute Set
- GameplayAttributeData : 단일 프로퍼티
- Base Value
- Current Value : 버프등으로 인한 변동값
- ASC는 등록될 때, Owner에있는 Attribute Set 객체들을 자동으로 등록함 ( ASC variable과 동일한 클래스 내에서 )
-> 그냥 variable 선언하고, CreateDefaultSubobject로 할당하면됨
-> ASC->GetSet<class>()
- Attribute Set class 안에있는 매크로 참조하여 사용. 아래쪽에 전처리#def 해서 getter, setter, inniter 자동생성 매크로 있음
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, AttackRange);
- PreAttributeChange, PostAttributeChange등의 가상함수를 제공
- MetaAttribute
- 확장성을 위해 중간단계에 추상성 계산단계를 추가
- ex. 공격로직을 hp에 직접 적용하지 않고 공격로직 -> Damage attritue -> hp attribute 등 ( 회복, 쉴드 등 추가개념 확장을 위해. 데미지는 음수가된다고 회복처리가 아니어야 함 )
- PostGameplayEffectExecution 함수에는 Effect에 의해 Modi된 값이 들어옴
- delegate 선언 시 mutable 선언을 통해서 const를 뺀 get/set에 접근
- Data.Target.AddLosseGameplayTag로 태그추가가능
10. GE ( Gameplay Effect )
- GA에서 MakeOutgoingGameplayEffectSpec(GE클래스) 만들어서 핸들러로 사용
-> ApplyGameplayEffectSpecToTarget
- 기본타입(DurationPolicy) : instant, duration, infinite
- 모디파이어로 어트리뷰트 변형방법을 지정 ( 혹은 GameplayEffectExecutionCalculation을 통해 커스텀 )
-> .Attribute, .ModifierOp -> FGameplayEffectModifierMagnitude타입 변수를 생성 -> [Modifier].ModifierManitude = 해당변수
-> MagnitudeType - Custom Calc Class : Gameplay Mod Magnitude Calculator를 참조
- 로직보단 세팅위주여서 BP를 권장
- DataTag를 통해서도 호출가능
( GE에 DataTag 등록 -> EffectSpecHandle.Data->SetSetbyCallerMagnitude(태그, attribute ), 다음 apply )
- GEContext : 정보를 담은 객체 ( instigator, causer, hit result 등 )
- GESpec : GE관련 정보 ( level, modifier, tag, context handle 등 )
-> GESpecHandle -> GESpec -> GEContextHandle -> GEContext ( GA없이 ASC가 직접 접근도 가능 )
-> 그래서 GEContext만들고, handle만든다음, 해당핸들을 param으로 GESpec 생성하고, GESpecHandle 생성
FGameplayEffectContextHandle EffectContextHandle = ASC->MakeEffectContext();
EffectContextHandle.AddSourceObject(this);
FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(InitStatEffect, Level, EffectContextHandle);
if (EffectSpecHandle.IsValid())
{
ASC->BP_ApplyGameplayEffectSpecToSelf(EffectSpecHandle);
}
- type이 Instance거나, bisPeriod = true인 경우에는 base value를 바꾸지만, 아닌 경우에는 current value 변경(버프취급)
11. GC ( Gameplay Cue )
- VFX나 SFX같이 로직과 상관없는 애들
- Static GC 순간발생
- Actor GC 기간발생
- Tag를 통해 발동시킬떄는, GameplayCue로 시작하는 태그를 사용해야 함
- GA에서 GCParam을 만들고, 해당파람.EffectContext에 GEContextHandle을 주입 -> ASC->ExecutecuteGameplayCue()
ps.
float 유효범위 정의 : FString::Printf(TEXT("%.0f / %0.f"), float, float)