1. 게임플레이 이펙트 컨텍스트(Gameplay Effect Context)
(1) 정의
게임플레이 이펙트 컨텍스트는 게임플레이 이펙트가 발생한 맥락에 대한 정보를 가진다.
(2) 구성 요소
- 발생 주체(Instigator) :이펙트를 발생한 주체(ASC를 가지고 있는 클래스)
- EffectCauser : 이펙트를 일으킨 객체(데미지를 주는 것, 투사체 등)
- 대상(Target)
- 발생 위치(Origin) : 기본적으로 0
- 어빌리티 레벨 : 기본적으로 1
- HitResult 구조체 : 설정하지 않으면 nullptr
(3) 게임플레이 이펙트 컨텍스트 핸들(Gameplay Effect Context Handle)
게임플레이 이펙트 컨텍스트의 래퍼.
컨텍스트를 안전하게 복사하고 전달한다.
레퍼런스 카운팅을 통해 메모리 관리가 자동으로 이루어진다.
(4) 활용 - AuraProjectileSpell 게임플레이 어빌리티 클래스
게임플레이 이펙트 컨텍스트 핸들에 기본적으로 존재하는 멤버 변수들에 정보를 담아 전송할 수도 있다.
// TODO : 투사체에 게임플레이 이펙트 스펙 붙이기 - 데미지 부여
const UAbilitySystemComponent* SourceASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetAvatarActorFromActorInfo());
FGameplayEffectContextHandle EffectContextHandle = SourceASC->MakeEffectContext();
EffectContextHandle.SetAbility(this);
EffectContextHandle.AddSourceObject(Projectile);
FHitResult HitResult;
EffectContextHandle.AddHitResult(HitResult);
위와 같이 정보를 설정하여 다른 클래스에서 다른 클래스로 쉽게 접근할 수 있다.
2. 커스텀 게임플레이 이펙트 컨텍스트 - AuraAbilityTypes
게임 내에 블록과 크리티컬 적중 시스템을 추가하였으므로, 이펙트 컨텍스트를 통해 이 효과들이 발동했는지에 대한 불리언을 넣으려고 한다.
또한 이런 정보들을 담아 서버로 전송하기 위해 직렬화(Serialize)도 오버라이드 한다.
#pragma once
#include "GameplayEffectTypes.h"
#include "AuraAbilityTypes.generated.h"
USTRUCT(BlueprintType)
struct FAuraGameplayEffectContext : public FGameplayEffectContext
{
GENERATED_BODY()
public:
// 구조체를 리플렉션 시스템에 사용하기 위해 반드시 오버라이드
virtual UScriptStruct* GetScriptStruct() const override { return FGameplayEffectContext::StaticStruct(); }
// 직렬화를 커스텀하기 위해 반드시 오버라이드
virtual bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) override;
bool IsCriticalHit() const { return bIsCriticalHit; }
bool IsBlockedHit() const { return bIsBlockedHit; }
void IsCriticalHit(bool bInIsCriticalHit) { bIsCriticalHit = bInIsCriticalHit; }
void IsBlockedHit(bool bInIsBlockedHit) { bIsBlockedHit = bInIsBlockedHit; }
protected:
UPROPERTY()
bool bIsBlockedHit = false;
UPROPERTY()
bool bIsCriticalHit = false;
};
(1) 직렬화(Serialize)란?
서버와 통신하기 위해 데이터를 이진수 또는 String으로 눌러 담는 것을 뜻한다.
(1-1) '<<(Left-Shift)' 연산자 오버로딩
FArchive 구조체에서는 '<<' 연산자가 오버로딩되어 있다.
이 연산자를 이용해 데이터를 직렬화(데이터 저장)하거나 역직렬화(데이터 가져오기) 할 수 있다.
(1-2) 비트 연산 - '<<' ; Shift Left
모든 비트를 오른쪽의 수 만큼 왼쪽으로 민다.
(1-3) 비트 연산 - '|=' ; Bitwise OR Equal
Bitwise OR는 두 값을 비교해 둘 중 하나라도 1이면 1을 표기한다.
직렬화는 비트를 오른쪽 끝에서부터 1로 채우고 한 자리씩 옮김으로써 각 이진수 한 개에 한 개의 정보를 저장할 수 있게 한다.
즉 0, 1로 저장되는 불리언들을 모아서 직렬화를 통해 비트로 전환하여 저장할 수 있게 된다.
(1-4) 비트 연산 - '&' ; Bitwise AND
저장 중이 아닐 때 데이터를 불러오기 위해 사용한다.
Bitwise AND는 두 값을 비교해 둘 다 1일 때만 1로 표기한다.
즉 오른쪽 끝부터 1비트씩을 이동시킨 후 & 연산자를 이용하여 값이 0인지 1인지 체크할 수 있게 된다.
(2) NetSerialize 함수 오버라이드
새로 추가한 두 개의 불리언 멤버 변수를 직렬화하기 위해 직렬화 함수를 오버라이드한다.
기본적인 내용은 부모의 것을 가져오고 값만 변경 및 추가한다.
#include "AuraAbilityTypes.h"
bool FAuraGameplayEffectContext::NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess)
{
uint32 RepBits = 0;
if (Ar.IsSaving())
{
if (bReplicateInstigator && Instigator.IsValid())
{
RepBits |= 1 << 0;
}
if (bReplicateEffectCauser && EffectCauser.IsValid())
{
RepBits |= 1 << 1;
}
if (AbilityCDO.IsValid())
{
RepBits |= 1 << 2;
}
if (bReplicateSourceObject && SourceObject.IsValid())
{
RepBits |= 1 << 3;
}
if (Actors.Num() > 0)
{
RepBits |= 1 << 4;
}
if (HitResult.IsValid())
{
RepBits |= 1 << 5;
}
if (bHasWorldOrigin)
{
RepBits |= 1 << 6;
}
// 커스텀 불리언 변수
if (bIsBlockedHit)
{
RepBits |= 1 << 7;
}
if (bIsCriticalHit)
{
RepBits |= 1 << 8;
}
}
// 9개의 비트 직렬화
Ar.SerializeBits(&RepBits, 9);
if (RepBits & (1 << 0))
{
Ar << Instigator;
}
if (RepBits & (1 << 1))
{
Ar << EffectCauser;
}
if (RepBits & (1 << 2))
{
Ar << AbilityCDO;
}
if (RepBits & (1 << 3))
{
Ar << SourceObject;
}
if (RepBits & (1 << 4))
{
SafeNetSerializeTArray_Default<31>(Ar, Actors);
}
if (RepBits & (1 << 5))
{
if (Ar.IsLoading())
{
if (!HitResult.IsValid())
{
HitResult = TSharedPtr<FHitResult>(new FHitResult());
}
}
HitResult->NetSerialize(Ar, Map, bOutSuccess);
}
if (RepBits & (1 << 6))
{
Ar << WorldOrigin;
bHasWorldOrigin = true;
}
else
{
bHasWorldOrigin = false;
}
if (RepBits & (1 << 7))
{
Ar << bIsBlockedHit;
}
if (RepBits & (1 << 8))
{
Ar << bIsCriticalHit;
}
if (Ar.IsLoading())
{
AddInstigator(Instigator.Get(), EffectCauser.Get());
}
bOutSuccess = true;
return true;
}
'UE 5 스터디 > Gameplay Ability System(GAS)' 카테고리의 다른 글
12-3. 커스텀 어빌리티 시스템 글로벌(Aura Ability System Globals) (0) | 2024.12.24 |
---|---|
12-2. 게임플레이 이펙트 컨텍스트 - (2) 구조체 직렬화(Struct Ops Type Traits) (1) | 2024.12.24 |
11-12. 데미지 실행 계산(Execution Calculation) - (4) 크리티컬 계산 (0) | 2024.12.23 |
11-11. 데미지 실행 계산(Execution Calculation) - (3) 블록 확률, 방어력, 방어 관통 (0) | 2024.12.19 |
11-10. 데미지 실행 계산(Execution Calculation) - (2) 속성 캡쳐(Capturing Attributes) (0) | 2024.12.19 |