[UE5] GAS(Game Ability System)

GamzaTori·2024년 11월 20일

UE5 C++

목록 보기
25/27

GAS(Game Ability System)

  • 복잡한 스킬과 상태 효과를 쉽게 관리하고 구현할 수 있도록 돕는 프레임워크
  • 능력(Ability), 효과(Effect), 속성(Attribute)등의 개념을 중심으로 작동합니다.
  • 클라이언트와 서버 간의 동기화 작업을 자동으로 처리해주기 때문에 네트워크 게임 환경에서도 안정적인 성능을 유지할 수 있습니다.
  • GAS는 모듈식 구조로 확장성과 재사용성이 뛰어납니다.
  • 능력 발동 중 다른 능력이 겹치지 않도록 처리하거나 복잡한 효과를 관리할 수 있습니다.

Ability

  • 게임 내 캐릭터가 사용할 수 있는 동작이나 스킬
  • 시작, 실행, 종료라는 기본 단계를 가지고 있으며 조건부로 발동될 수 있다.

Attribute

  • 캐릭터의 상태를 나타내는 값으로 예를 들어 체력, 마나, 스태미나같은 스탯이 있습니다.
  • 속성은 능력이나 효과의 영향을 받으며 게임 내 캐릭터의 능력 발동과 직접적으로 연결됩니다.

Effect

  • 능력이 발동될 때 일시적 또는 지속적인 변화를 캐릭터에게 부여하는 요소
  • 예를 들어 공격력 증가, 체력 회복, 상태 이상 등
  • 효과는 속성에 직접적인 변화를 주어 특정 시간 동안 유지되거나 조건에 따라 종료됩니다.

Gameplay Tags

  • 스킬을 Skill_Attack_Fireball 처럼 태그를 이용해서 관리할 수 있습니다.
  • 능력 발동 조건이나 제한, 효과 적용 조건 등에 쓰임
  • CanAttack, Stunned 같은 태그를 사용하여 특정 능력을 발동 시킬 수 있는지를 관리할 수 있습니다.

GAS를 사용하기 위해 Gameplay Abilites plugin 추가

  • Edit -> Plugin
  • bulid.cs에 GameplayTas, GameplayTasks, GameplayAbilities 모듈 추가

AbilitySystemComponent를 상속받은 클래스 생성

  • 스킬코드를 관리하는 매니저같은 역할
  • 꼭 플레이어의 스킬만이 아닌 몬스터 스킬, 버프도 관리 대상이 될 수 있다.
  • 해당 컴포넌트를 몬스터와 플레이어의 상위 클래스인 캐릭터 클래스에서 관리하는 것이 좋다.
#include "AbilitySystemInterface"

class My_API AMyCharacter: public Character, public IAbilitySystemInterface
{    
public:
	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    virtual void InitAbilitySystem();		// 몬스터나 플레이어가 오버라이드 해서 사용
    
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	TObjectPtr<class UMyAbilitySystemComponent> AbilitySystemComponent;
}

// cpp
UAbilitySystemComponent* AR1Character::GetAbilitySystemComponent() const
{
	return AbilitySystemComponent;
}

  • 게임 어빌리티 시스템 컴포넌트를 들고있다는 힌트를 주기 위해 IAbilitySystemInterface를 상속받는다
  • AbilitySystemComponent는 몬스터는 몬스터의 클래스에서 생성해도 되지만 Player는 PlayerState 클래스에서 들고 있도록 하는 것이 좋다
    • PlayerState는 네트워크를 통해 동기화되기 때문에 게임 플레이 중에도 정보를 유지할 수 있고, 캐릭터를 바꾸거나 죽더라도 어빌리티 시스템을 지속적으로 유지할 수 있도록 합니다.

몬스터에서 AbilitySystemComponent 만들고 초기화하기

AMyMonster::AMyMonster()
{
	GetMesh()->SetRelativeLocationAndRotation(FVector(0.f, 0.f, -88.f), FRotator(0.f, -90.f, 0.f));

	AbilitySystemComponent = CreateDefaultSubobject<UMyAbilitySystemComponent>("AbilitySystemComponent");
    // 레플리케이션 여부도 설정해 네트워크에서 동기화할 수 있다
    // AbilitySystemComponent->SetIsReplicated(true);
}

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

	InitAbilitySystem();
}

void AMyMonster::InitAbilitySystem()
{
	Super::InitAbilitySystem();

	AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
  • InitAbilityActorInfo에는 어빌리티 시스템을 가지고있는 Owner와 실제로 컨트롤 되는 Avatar에 대한 정보를 전달해야한다.
  • 몬스터의 경우 실제로 어빌리티 시스템도 가지고 있고 컨트롤 되고 있는 아바타이기 때문에 둘 다 this를 전달하면 된다.

PlayerState Class를 상속받은 클래스 생성

  • 플레이어의 상태를 제어하는 클래스
// h
public:
	AMyPlayerState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

public:
	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	TObjectPtr<class UMyAbilitySystemComponent> AbilitySystemComponent;
   
// cpp
AMyPlayerState::AMyPlayerState(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	AbilitySystemComponent = CreateDefaultSubobject<UMyAbilitySystemComponent>("AbilitySystemComponent");
}

UAbilitySystemComponent* AMyPlayerState::GetAbilitySystemComponent() const
{
	return AbilitySystemComponent;
}
  • AbilitySystemComponent의 원본은 PlyaerState에서 만들어서 플레이어에서 참조할 수 있도록 한다.

GameMode에서 만들어준 PlayerState 클래스 적용

  • 별도로 Player와 PlayerState를 연결해주지 않아도 된다.

Player에 AbilitySystemComponent 추가

// h
protected:
	virtual void PossessedBy(AController* NewController) override;
	virtual void InitAbilitySystem() override;
    
// cpp
void AMyPlayer::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	InitAbilitySystem();
}

void AMyPlayer::InitAbilitySystem()
{
	Super::InitAbilitySystem();

	if(AMyPlayerState* PS = GetPlayerState<AMyPlayerState>())
	{
		AbilitySystemComponent = Cast<UMyAbilitySystemComponent>(PS->GetAbilitySystemComponent());
        AbilitySystemComponent->InitAbilityActorInfo(PS, this);
	}
}
  • 플레이어가 PossessedBy 될 때 생성하는 이유는 플레이어가 소유된 시점에 AbilitySystemComponent가 생성되어 어빌리티와 상태 관련 기능들을 일관되게 처리하고 네트워크 상의 동기화를 보장하기 위함입니다.
profile
게임 개발 공부중입니다.

0개의 댓글