[Unreal Engine] Gameplay Ability

이매·2025년 5월 5일

Unreal GAS

목록 보기
4/7
post-thumbnail

Gameplay Ability의 정의

Gameplay Ability는 게임에서 액터가 수행할 수 있는 모든 행동이나 스킬입니다. 예를 들어, 질주하면서 총을 쏘는 것처럼 둘 이상의 GameplayAbility를 동시에 활성화할 수도 있습니다.

Gameplay Ability는 블루프린트 또는 C++에서 구현할 수 있습니다.

GameplayAbility의 예시:

  • 점프
  • 질주
  • 총 발사
  • 특정 초마다 수동으로 공격 막기
  • 포션 사용
  • 문 열기
  • 자원 수집
  • 건물 건설

Gameplay Ability의 생성 및 초기화

  • 간단한 Gameplay Ability의 로직(흐름도)

  • 심화된 Gameplay Ability의 로직(흐름도)


C++의 경우

우선 GameplayAbility 클래스를 부모로 삼는 GA_TestAbility를 생성하겠습니다.

// GA_TestAbility.h
#pragma once

#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "GA_Test.generated.h"

/**
* 
*/
UCLASS()
class GASTEMPLATE_API UGA_Test : public UGameplayAbility
{
GENERATED_BODY()


public:

	UGA_Test();

	/** 이 능력을 지금 활성화할 수 있는지 여부를 반환합니다. 부작용은 없습니다. */
	virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags = nullptr, const FGameplayTagContainer* TargetTags = nullptr, OUT FGameplayTagContainer* OptionalRelevantTags = nullptr) const override;

	/** 실행당 인스턴스화된 능력을 제거합니다. 액터당 인스턴스화된 능력은 '재설정'해야 합니다. 활성 상태의 능력 상태 태스크는 'OnAbilityStateInterrupted' 이벤트를 수신합니다. 비인스턴스 능력 - 무엇을 할 수 있을까요? */
	virtual void CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility) override;

	/** 능력을 커밋합니다. */
	virtual bool CommitAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, OUT FGameplayTagContainer* OptionalRelevantTags = nullptr) override;

	/** 실제로 Ability를 활성화합니다. 이 메서드를 직접 호출하지 마세요. */
	virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;

	/** Ability가 정상적으로 또는 비정상적으로 종료되었을 때 호출되는 네이티브 함수입니다. bReplicate가 true로 설정된 경우, 클라이언트/서버에 종료를 복제하려고 시도합니다. */
	virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
};
// GA_TestAbility.cpp
#include "GAS/Abilities/GA_Test.h"

UGA_Test::UGA_Test()
{
	// GameplayAbility가 활성화될 때마다 액터마다 새로운 인스턴스가 생성됩니다.
	InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; 
}

bool UGA_Test::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
{
	return true;
}

void UGA_Test::CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility)
{
}

bool UGA_Test::CommitAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, OUT FGameplayTagContainer* OptionalRelevantTags)
{
	return true;
}

void UGA_Test::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);

	UE_LOG(LogTemp, Warning, TEXT("GA_Test::ActivateAbility"));

	EndAbility(Handle, ActorInfo, ActivationInfo, true, false);
}

void UGA_Test::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
	Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);

	UE_LOG(LogTemp, Warning, TEXT("GA_Test::EndAbility"));
}

Gameplay Ability는 기본적으로 어빌리티를 실행, 취소, 종료, 확인 등을 위한 다양한 함수들을 기본적으로 제공하고 있습니다.

  • ActivateAbility : 어빌리티를 실행함. 자동적으로 호출
  • EndAbility : 어빌리티를 종료함.
  • CancelAbility : 어빌리티를 취소함.
  • CommitAbility : 어빌리티의 실행 자원이 사용 가능한 지 확인함. EX) 쿨타임, 자원소모 등
  • CanActivateAbility : 어빌리티가 실행될 수 있는 지 미리 판단함

Ability System Component(ASC)에서 TryActivateAbility함수를 통해 해당 어빌리티를 호출하면 자동적으로 ActiveAbility함수가 호출되어 어빌리티의 로직을 실행하게 됩니다.


블루프린트의 경우,

C++과 마찬가지로 GameplayAbility 클래스를 부모로 삼는 GA_TestAbility를 생성하면 됩니다.


Gameplay Ability 실행하기

어빌리티를 실행하기 위해서는 다음과 같은 과정이 필요합니다.

  1. Ability System Component(ASC)의를 소유한 액터에 GiveAbility를 통해 실행할 어빌리티를 등록하기
  2. Ability System Component(ASC)를 통해 TryActivateAbility로 등록한 어빌리티를 실행하기

C++의 경우,

// YourCharacter.h
class AGASTemplateCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()
    
    ...
    
    // 어빌리티 시스템 컴포넌트에 추가할 어빌리티입니다.
	UPROPERTY(EditAnywhere, Category = GAS)
	TSubclassOf<class UGameplayAbility> Ability;
    
// YourCharacter.cpp
#include "GAS/Abilities/GA_Test.h"

...

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

	// 캐릭터가 소유한 AbilitySystemComponent를 초기화합니다.
	if (AbilitySystemComponent)
	{
		// OnwerActor : 캐릭터 자신, AvatarActor : 캐릭터 자신
		AbilitySystemComponent->InitAbilityActorInfo(this, this);

		// AbilitySystemComponent에 Ability를 등록합니다.
		FGameplayAbilitySpec TestAbilitySpec(UGA_Test::StaticClass());
		AbilitySystemComponent->GiveAbility(TestAbilitySpec);
	}
}

void AGASTemplateCharacter::ActiveAbility(const FInputActionValue& Value)
{
	bool BoolValue = Value.Get<bool>();

	if (BoolValue)
	{
		// AbilitySystemComponent에서 UGA_Test Ability를 찾습니다.
		FGameplayAbilitySpec* AbilitySpec = AbilitySystemComponent->FindAbilitySpecFromClass(UGA_Test::StaticClass());
		if (AbilitySpec)
		{
			// Ability를 실행합니다.
			AbilitySystemComponent->TryActivateAbility(AbilitySpec->Handle);							// Ability Spec을 통해 Ability를 실행합니다.
			//AbilitySystemComponent->TryActivateAbilityByClass(UGA_Test::StaticClass());				// Ability Class를 통해 Ability를 실행합니다.
			//AbilitySystemComponent->TryActivateAbilitiesByTag(FGameplayTagContainer::EmptyContainer); // Ability Tag를 통해 Ability를 실행합니다.
		}
		else
		{
			UE_LOG(LogTemplateCharacter, Error, TEXT("Failed to find ability spec for GA_Test"));
		}
	}
}

이러면 이제 ASC를 이용하여 우리가 원하는 어빌리티들을 실행할 수 있게 됩니다.


블루프린트의 경우,

  • AbilitySystemComponent에 Ability를 등록

  • 등록한 어빌리티를 TryActiveAbility를 통해 실행

실행 방법에도 총 3가지가 있습니다.

  1. AbilitySystemComponent에 등록된 Ability의 Spec Handle을 찾아서 실행
  2. Ability의 클래스 레퍼런스를 이용하여 실행
  3. Ability가 가진 Gameplay Tag 정보를 이용하여 실행

세가지 방법 모두 C++, 블루프린트에서 자유롭게 사용이 가능합니다.

Gameplay Tag에 대해서는 추후 더 자세히 다루겠습니다.


실행 결과

실행할 키를 바인드하고 어빌리티를 실행시켜보면 다음과 같이 로그가 뜨게 됩니다.

📘 TIP Gameplay Ability는 기본적으로 한프레임에 실행이 됩니다.
따라서 애니메이션이나 이벤트와 같은 대기 작업이 필요한 경우 Ability Task를 통해 지연 작업을 사용하게 됩니다.
Ability Task에 관한 내용 역시 추후에 더 자세히 다루겠습니다.

profile
언리얼 엔진 주니어(신입) 개발자 | 소설 쓰는 취준 개발자

0개의 댓글