언리얼/게임 프로젝트

GameplayAbilitySystem을 이용한 RPG 프로젝트 - (14) GameplayEffect와 EffectActor 코드 수정

monstro 2024. 12. 1. 21:23
728x90
반응형

본격적인 GameplayEffect를 적용하기 전에 GameplayEffect가 무엇이고 어떻게 동작하는지 알아보겠습니다.

 

1) GameplayEffect

GAS 프레임워크에서는 게임에 영향을 주는 객체를 별도로 분리해서 관리합니다.

이때 별도로 분리되는 객체를 GameplayEffect로서 사용합니다.

GameplayEffect를 정의하는 클래스들은 데이터 전용 클래스이므로 따로 로직을 추가해서는 안됩니다.

 

GameplayEffect에는 Duration Policy가 존재하여 이를 통해 GE를 적용하는 기간을 결정합니다.
InstantAttribute에 즉각 적용되며, 한 프레임에서만 실행됩니다.
Has Duration지정한 시간동안 적용되는 GE에 사용합니다.

Inifite명시적으로 종료하지 않으면 계속 동작하는 GE에 사용합니다.

 

GE는 2가지의 방식을 통해 Attribute를 변경합니다.

1) Modifer

첫 번째 방법은 Modifer입니다.

사용방법은 총 4가지로 정의할 수 있습니다.

  • Add : 더하기
  • Multiply : 곱하기
  • Divide : 나누기
  • Override : 덮어씌우기

위의 4가지 방법을 통해 지정한 Attribute에 사용할 수 있습니다.

이때 사용방법의 계산 방식을 정의할 수 있는데,

계산 방식 역시 총 4가지로 정의할 수 있습니다.

  • Scalable Float : 실수값으로 계산 
  • AttributeBased : 특정한  Attribute에 기반하여 계산
  • CustomCalculationClass : 계산을 담당하는 전용 클래스를 통해 계산
  • SetByCaller : 데이터 태그를 활용한 데이터를 전달

이런 Modifier를 사용하는 경우 C++로 사용하는 경우 문법이 복잡하므로,

블루 프린트를 사용하는 것이 더 간단할 수 있습니다.

2) GameplayEffectExecutionCaculation

Modifier 없이 자체 계산 로직을 만들어 계산하는 것도 가능합니다.

 

위에서 언급된 Attribute를 변경 하는 것외에도 GameplayEffect에서 수행할 수 있는 여러개의 동작이 있습니다.

Stacking, Add Gameplay Tags, Grant Abilitie 등이 대표적이며 추후에 알아보도록 하겠습니다.

 

마지막으로 GameplayEffect는 GE 단독으로 사용하기 보다는 

GameplayEffectSpec의 Wrapper 클래스의 형태로 경량화하여 사용하는 것이 좋습니다.

기본적으로 GE에 비해서 많은 정보를 담고 있고 다루기 쉽기 때문

프로젝트에서도 GameplayEffectSpec의 형태로 자주 사용하도록 하겠습니다.

 

 

2) 기존의 EffectActor를 수정

AuraEffectActor의 코드의 기존의 문제점은 만들어진 틀에서 벗어나기 힘들고,

억지적으로 const를 없앤 채로 attribute를 변경하는 것이었습니다.

따라서 이를 위해 코드를 일부 수정하고 추가적으로 블루 프린트도 수정하겠습니다.

 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AuraEffectActor.generated.h"

class UGameplayEffect;

UCLASS()
class AURA_API AAuraEffectActor : public AActor
{
	GENERATED_BODY()
	
public:	
	AAuraEffectActor();


protected:
	virtual void BeginPlay() override;

	/*
	* Gameplay Effect Section
	*/
	UFUNCTION(BlueprintCallable)
	void ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass);

	UPROPERTY(EditAnywhere, Category = "Applied Effects")
	TSubclassOf<UGameplayEffect> InstantGameplayEffectClass;
};

 

기존의 코드에서의 Sphere와 Mesh 그리고

Sphere에서 BeingOverlap과 EndOverlap시에 발동하는 콜백함수들도 삭제하였습니다.

 

대신 Overlap되는 경우 발동할 함수 ApplyEffectToTarget 함수

적용할 GameplayEffectInstantGameplayEffectClass를 사용하도록 하겠습니다.

 

#include "Actor/AuraEffectActor.h"
#include "AbilitySystem/AuraAttributeSet.h"
#include "AbilitySystemBlueprintLibrary.h"

AAuraEffectActor::AAuraEffectActor()
{
	PrimaryActorTick.bCanEverTick = false;

	SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot")));
}

void AAuraEffectActor::BeginPlay()
{
	Super::BeginPlay();


}

void AAuraEffectActor::ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
	UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target);
	if (TargetASC)
	{
		FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
		EffectContextHandle.AddSourceObject(this);
		const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.0f, EffectContextHandle);
		TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
	}
}

 

생성자에서는 SceneComponent를 생성하고 이를 RootComponent로 설정합니다.

이 경우 EffectActor에서 생성되는 블루 프린트들은 더욱더 자유로운 설계가 가능해집니다.

 

중요한 것은 ApplyEffectToTarget 함수입니다.

GetAbilitySystemComponent 함수를 통해 Target의 ASC를 가져옵니다.

가져온 ASC가 nullptr가 아니라면 로직을 수행하겠습니다.

 

우선 GameplayEffectContext의 WrapperClassFGameplayEffectContextHandleASC로부터 생성합니다.

생성된 FGameplayEffectContextHandleEffect의 생성 주체AddSourceObject 함수로 설정합니다.

 

그후에 ASC로부터 MakeOutgoingSpec 함수를 호출하여

EffectSpec을 감싼 Wrapper 클래스인 GameplayEffectSpecHandle을 생성합니다.

이때 인자는 GameplayEffect, GE의 레벨, GameplayEffectContextHandle 입니다.

 

최종적으로 생성된 GameplayEffectSpecHandle로부터 GamePlayEffectSpec을 사용해야 합니다.

이를 위해 생성된 EffectSpecHandle로부터 Data.Get() 함수

GameplayEffect를 가리키는 포인터를 가져오고 이 포인터가 참조하고 있는 데이터를 ASC의 함수 ApplyGameplayEffectSpecToSelf 에 넘겨주어 EffectActor에 GE를 적용하겠습니다.

 

이후 빌드한뒤, Effect Actor의 블루 프린트를 변경하겠습니다.

 

3) 언리얼 에디터

 

기존의 구성에서 위와 같이 컴포넌트 구조를 변경하였습니다.

Static Mesh를 추가하고 여기에 Sphere Collider를 추가하였습니다.

이때 Static Mesh의 Collision 설정은 꺼버리고

 

Sphere Collider의 Collision 설정은 켜두겠습니다.

 

이후 Sphere Collider를 선택하고 Event Graph에서 OnComponentBeginOverlap 함수를 추가하면

 

모든 설정이 완료됩니다.

이제 BeginOverlap 이후에 적용할 GE를 설정하겠습니다.

728x90
반응형