UE5/GAS

게임플레이 어빌리티 스펙

뽀또치즈맛 2025. 6. 9. 22:51

 

 

1. 스펙(Spec)이란?

  • 스펙(Spec)은 게임플레이 어빌리티(Ability)에 대한 정보를 담고 있는 구조체입니다.
  • ASC(Ability System Component)는 어빌리티 인스턴스를 직접 참조하지 않고, 스펙 정보만을 가지고 관리합니다.
  • 스펙은 어빌리티의 현재 상태 등 다양한 정보를 포함합니다.
  • ASC에서 어빌리티를 제어할 때는, 스펙에 포함된 Handle 값을 사용해 컨트롤합니다.
  • 핸들 값은 전역으로 관리되며, 스펙이 생성될 때마다 1씩 증가합니다. 기본값은 -1이며,
    이는 잘못된 핸들인지 여부를 판별하는 데 사용됩니다.
  • 요약
    • 어빌리티 정보: 스펙(Spec)
    • 어빌리티 인스턴스 레퍼런스: 스펙 핸들(Handle)

2. 어빌리티 시스템 컴포넌트의 입력 처리

  • 게임 어빌리티 스펙에는 입력 값을 지정할 수 있는 필드인 InputID가 제공됩니다.
  • InputID를 통해 모든 GAS(게임 어빌리티 시스템)에서 일관된 방식으로 입력 처리를 할 수 있습니다.

입력 처리 순서:

  1. 입력 발생
    • 사용자의 입력이 들어오면, ASC는 등록된 스펙 중에서 입력에 매핑된 GA(게임 어빌리티)를 찾습니다.
    • → FindAbilitySpecFromInputID 함수 사용
  2. GA 발동 상태 체크
    • 해당 GA가 이미 발동 중이면, 입력 신호를 GA에 전달합니다.
      • → AbilitySpecInputPressed
    • GA가 발동 중이 아니라면, 어빌리티를 새로 발동시킵니다.
      • → TryActivateAbility
  3. 입력 해제 처리
    • 입력이 해제되면, 동일하게 GA에 입력 해제 신호를 전달합니다.
      • → AbilitySpecInputReleased
  • EnhancedInputComponent의 BindAction 함수를 활용하면 이러한 입력 처리를 범용적으로 쉽게 구현할 수 있습니다.

 


게임플레이 어빌리티의 인스턴싱 옵션

상황에 따라 어빌리티의 인스턴스 생성(Instancing) 정책을 선택할 수 있습니다.

1. NonInstanced

  • 설명: 별도의 인스턴스 없이 CDO(Class Default Object)에서 모든 로직을 처리합니다.
  • 특징: 상태를 가지지 않는, 완전히 동일한 어빌리티에 적합합니다.

2. InstancedPerActor

  • 설명: 액터(플레이어 등)마다 하나의 어빌리티 인스턴스를 생성해서 관리합니다.
  • 특징: 각 액터가 고유의 어빌리티 상태를 가질 수 있으며, 네트워크 리플리케이션(동기화)까지 고려했을 때 가장 무난한 선택입니다.
  • 별칭: Primary Instance

3. InstancedPerExecution

  • 설명: 어빌리티가 발동될 때마다 새로운 인스턴스를 생성해서 처리합니다.
  • 특징: 어빌리티 사용 시마다 별도 상태나 임시 데이터를 저장해야 할 때 유용합니다.

네트워크 리플리케이션(동기화) 고려

  • InstancedPerActor 옵션은 액터마다 하나의 어빌리티 인스턴스를 생성해 처리하므로,
  • 클라이언트와 서버 간의 상태 동기화 및 관리가 용이합니다.
  • 실무적으로 네트워크 게임에서는 InstancedPerActor가 가장 널리 사용됩니다.

 

1. NonInstanced 예시

상황

  • 어빌리티가 상태를 가지지 않고, 전역적으로 동일한 동작만 하면 되는 경우
    (ex. 모든 플레이어가 동일하게 적용되는 버프, 단순 효과)

코드 예시

// 헤더 파일에서 인스턴싱 정책 지정
AbilityInstancingPolicy = EGameplayAbilityInstancingPolicy::NonInstanced;

// 실제 C++ 클래스 선언부
UCLASS()
class UGA_NonInstanced : public UGameplayAbility
{
    GENERATED_BODY()
public:
    // 상태를 저장하지 않는 순수 효과 예시
    virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, 
                                 const FGameplayAbilityActorInfo* ActorInfo, 
                                 const FGameplayAbilityActivationInfo ActivationInfo, 
                                 const FGameplayEventData* TriggerEventData) override
    {
        // 효과만 적용
        // ex: 체력 +10
    }
};

 

 

2. InstancedPerActor 예시

상황

  • 각 액터(플레이어/몬스터 등)별로 어빌리티의 상태(쿨타임, 카운터, 스택 등)가 필요할 때
  • 네트워크 멀티플레이에서 동기화가 중요한 어빌리티

코드 예시

AbilityInstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;

UCLASS()
class UGA_InstancedPerActor : public UGameplayAbility
{
    GENERATED_BODY()
public:
    // 액터마다 개별 상태를 가짐
    int32 CooldownCount;

    virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, 
                                 const FGameplayAbilityActorInfo* ActorInfo, 
                                 const FGameplayAbilityActivationInfo ActivationInfo, 
                                 const FGameplayEventData* TriggerEventData) override
    {
        CooldownCount++;
        // ex: 쿨타임 적용 등 액터별 상태 관리
    }
};

 

3. InstancedPerExecution 예시

상황

  • 어빌리티가 매번 발동 시마다 개별 임시 상태나 데이터를 관리해야 할 때
    (ex. 발동 중에만 유지되는 임시 변수, 여러 번 동시 발동 가능)

코드 예시

AbilityInstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerExecution;

UCLASS()
class UGA_InstancedPerExecution : public UGameplayAbility
{
    GENERATED_BODY()
public:
    // 매 실행마다 개별 데이터 관리
    float Duration;

    virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, 
                                 const FGameplayAbilityActorInfo* ActorInfo, 
                                 const FGameplayAbilityActivationInfo ActivationInfo, 
                                 const FGameplayEventData* TriggerEventData) override
    {
        Duration = 2.0f; // 예: 이번 실행에만 사용되는 타이머
        // 이 인스턴스는 곧 GC됨
    }
};

 

 

정리

  • NonInstanced : 상태 불필요, 가볍고 단순 효과용
  • InstancedPerActor : 액터마다 별도 상태 필요, 네트워크 동기화에 적합(가장 일반적)
  • InstancedPerExecution : 발동마다 개별 데이터 필요, 여러 번 동시 발동 가능