[Unreal Engine 5] GAS(Gameplay Ability System)

2026. 1. 26. 21:29·프로그래밍/Unreal Engine 5

GAS는 멀티플레이어 동기화(Replication), 복잡한 스킬 상호작용, 스탯 관리를 처리할 수 있는 프레임워크이다. "포트나이트"나 "파라곤" 같은 게임들이 이 시스템 위에서 돌아가고 있다.


1. 개념 및 설계: GAS의 3대장

GAS를 이해하려면 다음 세 가지 핵심 요소를 알아야 한다.

  1. Ability System Component (ASC): 모든 GAS 기능의 중추. 캐릭터(Actor)에 부착되어 스킬 사용, 스탯 변경 등을 총괄.
  2. Attribute Set: 체력(HP), 마나(MP), 공격력 등 수치 데이터를 관리.
  3. Gameplay Ability (GA) & Effect (GE): 실제로 실행되는 스킬 로직(GA)과 스탯을 변경하는 효과(GE).


2. 모듈 설정 (Build.cs)

GAS는 기본적으로 활성화되어 있지 않다. C++ 프로젝트라면 Build.cs 파일에 필수 모듈을 추가해야 함.

[ProjectName].Build.cs

public class MyProject : ModuleRules
{
    public MyProject(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { 
            "Core", 
            "CoreUObject", 
            "Engine", 
            "InputCore", 
            "EnhancedInput",
            // GAS 필수 모듈 3가지
            "GameplayAbilities", 
            "GameplayTags", 
            "GameplayTasks" 
        });
    }
}
  • 코드를 수정 후 라이더(Rider)나 에디터에서 'Refresh Visual Studio Project'를 실행하거나 빌드를 다시 해야 인텔리센스가 정상 작동.

3. Attribute Set 구현 (스탯 관리)

언리얼은 Attribute 관리를 위해 복잡한 매크로를 사용한다.

MyAttributeSet.h

#pragma once

#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "MyAttributeSet.generated.h"

// 보일러플레이트 매크로: Getter, Setter, Init 함수 자동 생성
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

UCLASS()
class MYPROJECT_API UMyAttributeSet : public UAttributeSet
{
    GENERATED_BODY()

public:
    UMyAttributeSet();

    // 리플리케이션(네트워크 동기화)을 위한 필수 오버라이드
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

    // 값이 변경되기 전/후 처리 (예: HP < 0 방지)
    virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

    // --- 체력 속성 정의 ---
    UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_Health)
    FGameplayAttributeData Health;
    ATTRIBUTE_ACCESSORS(UMyAttributeSet, Health);

    UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_MaxHealth)
    FGameplayAttributeData MaxHealth;
    ATTRIBUTE_ACCESSORS(UMyAttributeSet, MaxHealth);

protected:
    // 값이 서버에서 변경되어 클라이언트로 왔을 때 호출됨
    UFUNCTION()
    virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);

    UFUNCTION()
    virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
};

MyAttributeSet.cpp

#include "MyAttributeSet.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
#include "Logging/StructuredLog.h" // UE_LOGFMT 사용

UMyAttributeSet::UMyAttributeSet()
{
    // 초기값 설정 (나중에 데이터 테이블로 관리하는 것이 정석)
    InitHealth(100.0f);
    InitMaxHealth(100.0f);
}

void UMyAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // DOREPLLIFETIME_CONDITION_NOTIFY: 값이 바뀔 때만 전송하고 알림을 보냄
    DOREPLLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, Health, COND_None, REPNOTIFY_Always);
    DOREPLLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
}

void UMyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    Super::PostGameplayEffectExecute(Data);

    if (Data.EvaluatedData.Attribute == GetHealthAttribute())
    {
        // 체력은 0과 MaxHealth 사이여야 함
        SetHealth(FMath::Clamp(GetHealth(), 0.0f, GetMaxHealth()));

        // 로그 출력 (구조화된 로그 사용)
        UE_LOGFMT(LogTemp, Log, "Health Changed: {0}", GetHealth());
    }
}

void UMyAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
    // 예측(Prediction) 시스템을 위해 필수
    GAMEPLAYATTRIBUTE_REPNOTIFY(UMyAttributeSet, Health, OldHealth);
}

void UMyAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth)
{
    GAMEPLAYATTRIBUTE_REPNOTIFY(UMyAttributeSet, MaxHealth, OldMaxHealth);
}

4. 캐릭터에 GAS 탑재 (Source)

이제 캐릭터가 위에서 만든 AttributeSet과 AbilitySystemComponent를 가지도록 설정. 여기서 중요한 것은 IAbilitySystemInterface를 상속받는 것이다.

MyCharacter.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AbilitySystemInterface.h" // 필수 인터페이스
#include "MyCharacter.generated.h"

class UAbilitySystemComponent;
class UMyAttributeSet;

UCLASS()
class MYPROJECT_API AMyCharacter : public ACharacter, public IAbilitySystemInterface // 반드시 상속 받아야 함
{
    GENERATED_BODY()

public:
    AMyCharacter();

    // IAbilitySystemInterface 구현: 이 액터의 ASC를 반환
    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;

protected:
    virtual void BeginPlay() override;

    // 서버에서 빙의되었을 때 ASC 초기화
    virtual void PossessedBy(AController* NewController) override;

    // 클라이언트에서 PlayerState 등이 복제되었을 때 ASC 초기화
    virtual void OnRep_PlayerState() override;

private:
    // ASC 컴포넌트 선언
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS", meta = (AllowPrivateAccess = "true"))
    TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

    // AttributeSet 선언
    UPROPERTY()
    TObjectPtr<UMyAttributeSet> AttributeSet;

    // ASC 초기화 함수
    void InitAbilitySystem();
};

MyCharacter.cpp

#include "MyCharacter.h"
#include "AbilitySystemComponent.h"
#include "MyAttributeSet.h"

AMyCharacter::AMyCharacter()
{
    // ASC 생성
    AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
    // 중요: 캐릭터 상태가 복제되도록 설정 (멀티플레이)
    AbilitySystemComponent->SetIsReplicated(true);
    AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);

    // AttributeSet 생성
    AttributeSet = CreateDefaultSubobject<UMyAttributeSet>(TEXT("AttributeSet"));
}

UAbilitySystemComponent* AMyCharacter::GetAbilitySystemComponent() const
{
    return AbilitySystemComponent;
}

void AMyCharacter::PossessedBy(AController* NewController)
{
    Super::PossessedBy(NewController);

    // 서버 측 초기화
    InitAbilitySystem();
}

void AMyCharacter::OnRep_PlayerState()
{
    Super::OnRep_PlayerState();

    // 클라이언트 측 초기화
    InitAbilitySystem();
}

void AMyCharacter::InitAbilitySystem()
{
    if (AbilitySystemComponent)
    {
        // Owner와 Avatar 설정 (여기서는 캐릭터가 둘 다 역할 수행)
        // 만약 PlayerState를 쓴다면 InitAbilityActorInfo(PlayerState, this)가 됨
        AbilitySystemComponent->InitAbilityActorInfo(this, this);

        UE_LOGFMT(LogTemp, Log, "GAS Initialized for {0}", GetName());
    }
}

5. JetBrains Rider & 최적화 팁

  1. 매크로 코드 생성: ATTRIBUTE_ACCESSORS 매크로를 작성할 때, Rider는 이를 인식하지 못해 빨간 줄을 띄울 수 있다. 하지만 컴파일은 된다. Rider 설정에서 Unreal Engine 매크로 지원을 켜둬야 함.
  2. Generate Definition: .h에서 함수 선언 후 Alt + Enter -> Generate definition을 사용하면 .cpp로 즉시 이동하여 구현부를 만들어준다.
  3. Live Templates: UE_LOGFMT나 DOREPLLIFETIME 같은 반복 코드는 라이더의 'Live Templates'에 등록해두고 단축키로 불러쓰면 타이핑 실수를 줄여줍니다.

주의사항 :

  • Tick 사용 자제: 체력 회복 등을 구현할 때 Tick 함수에서 매 프레임 값을 더하면 안된다. GAS의 GameplayEffect (Duration/Infinite) 를 사용하여 'Period' 설정을 통해 1초마다 회복되게 처리하는 것이 훨씬 성능에 좋다.
  • Nullptr 체크: GetAbilitySystemComponent()를 호출할 때 항상 유효성을 검사.

'프로그래밍 > Unreal Engine 5' 카테고리의 다른 글

[Unreal Engine 5] Unreal Engine 5 VS Schmetterling Engine 2.0  (0) 2026.02.05
[Unreal Engine 5] UFUNCTION()와 지정자(Specfier)들  (0) 2026.01.29
[Unreal Engine 5] 충돌처리를 위해 바인딩(Binding)을 하는 이유  (0) 2026.01.23
[Unreal Engine 5] TSubclassOf<T>  (0) 2026.01.16
[Unreal Engine 5] UPROPERTY()와 지정자(Specifier)들  (0) 2026.01.15
'프로그래밍/Unreal Engine 5' 카테고리의 다른 글
  • [Unreal Engine 5] Unreal Engine 5 VS Schmetterling Engine 2.0
  • [Unreal Engine 5] UFUNCTION()와 지정자(Specfier)들
  • [Unreal Engine 5] 충돌처리를 위해 바인딩(Binding)을 하는 이유
  • [Unreal Engine 5] TSubclassOf<T>
hanong8
hanong8
hanong8 님의 블로그 입니다.
  • hanong8
    HaNong
    hanong8
  • 전체
    오늘
    어제
    • 분류 전체보기 (102) N
      • 프로그래밍 (99) N
        • Unreal Engine 5 (45)
        • C++ (22)
        • UML (2)
        • 자료구조 (2)
        • 알고리즘 (9)
        • 개발일지 (4)
        • DirectX11 (5)
        • Git (2)
        • 코드카타 (8) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hanong8
[Unreal Engine 5] GAS(Gameplay Ability System)
상단으로

티스토리툴바