게임플레이 어빌리티 시스템(Gameplay Ability System) 은 게임플레이 어트리뷰트(Gameplay Attributes) (FGameplayAttribute )를 사용하여 게임플레이 관련 부동 소수점 값을 저장, 계산, 수정합니다. 이 값은 캐릭터의 남은 생명력, 비히클의 최고 속력, 아이템이 파괴되기 전까지 사용 가능한 횟수 등 소유자의 어떤 특성이든 설명할 수 있습니다. 게임플레이 어빌리티 시스템의 액터는 게임플레이 어트리뷰트를 어트리뷰트 세트(Attribute Set) 에 저장합니다. 이는 어트리뷰트를 액터의 어빌리티 시스템 컴포넌트에 등록하고, 게임플레이 어트리뷰트와 시스템의 나머지 부분 간의 인터랙션을 관리하는 데 도움이 됩니다. 이러한 인터랙션에는 값 범위 제한, 일시적 값 변경을 적용하는 계산 수행, 영구적으로 베이스 값을 변경하는 이벤트에 대한 반응 등이 있습니다.

게임플레이 어트리뷰트

게임플레이 어트리뷰트에는 현재(current) 값과 베이스(base) 값이 저장됩니다. '현재' 값은 현재 활성화된 게임플레이 이펙트를 사용하고 이펙트에 영향받는 계산과 로직에 일반적으로 사용됩니다. '베이스' 값은 더 오랜 기간 고정된 채로 유지되는 경우가 많습니다. 예를 들어 '점프 높이' 게임플레이 어트리뷰트의 베이스 값은 100.0이지만, 캐릭터가 지쳐서 원래의 70% 높이까지만 점프할 수 있다는 게임플레이 이펙트가 활성화되었다면 현재 값은 70.0이 됩니다. 레벨업 시스템을 통해 캐릭터가 점프에 능숙해지면 베이스 값이 110.0으로 증가할 수도 있으며, 이때 캐릭터가 지쳤다는 게임플레이 이펙트가 남아 있다면 현재 값은 77.0으로 계산될 것입니다.

게임플레이 어트리뷰트를 생성하려면 우선 어트리뷰트 세트(Attribute Set)를 만들어야 합니다. 그런 다음 어트리뷰트 세트에 게임플레이 어트리뷰트를 추가할 수 있습니다.

<aside> 📌

경우에 따라서는 어트리뷰트 세트 없이도 게임플레이 어트리뷰트가 존재할 수 있습니다. 이 경우 일반적으로 적절한 게임플레이 어트리뷰트 타입을 포함하는 어트리뷰트 세트가 없는 어빌리티 시스템 컴포넌트(Ability System Component) 에 게임플레이 어트리뷰트가 저장된 것입니다. 이는 권장되지 않습니다. 게임플레이 어트리뷰트가 게임플레이 어빌리티 시스템과 상호작용하는 어떠한 행동도 정의되지 않은 채 부동 소수점 값으로만 저장되기 때문입니다.

</aside>

어트리뷰트 세트

정의 및 구성

우선 하나 이상의 게임플레이 어트리뷰트(Gameplay Attributes)로 어트리뷰트 세트(Attribute Set)를 구성하고, 어빌리티 시스템 컴포넌트(Ability System Component)에 등록합니다.

  1. 베이스 어트리뷰트 세트 클래스 UAttributeSet 를 확장하고 게임플레이 어트리뷰트를 FGameplayAttributeData UProperties로 추가합니다. 게임플레이 어트리뷰트가 하나 있는 단순한 어트리뷰트 세트는 다음과 같습니다.

    UCLASS()
    class MYPROJECT_API UMyAttributeSet : public UAttributeSet
    {
        GENERATED_BODY()
        
    	  public:
    	  /** 퍼블릭 액세스 가능한 샘플 어트리뷰트 'Health'*/
    	  UPROPERTY(EditAnywhere, BlueprintReadOnly)
    	  FGameplayAttributeData Health;
    };
    
  2. 어트리뷰트 세트를 액터에 저장하고 엔진에 노출합니다. const 키워드를 사용하여 코드가 어트리뷰트 세트를 직접 수정하지 못하게 합니다. 액터의 클래스 정의에 다음을 추가합니다.

    /** 샘플 어트리뷰트 세트. */
    UPROPERTY()
    const UMyAttributeSet* AttributeSet;
    
  3. 어트리뷰트 세트를 적절한 어빌리티 시스템 컴포넌트로 등록합니다. 액터 생성자에서 어트리뷰트 세트를 인스턴스화하는 시점에 액터의 GetAbilitySystemComponent 함수가 유효한 어빌리티 시스템 컴포넌트를 반환하는 한, 인스턴스화 시점이나 BeginPlay 도중에 자동으로 등록됩니다. 액터의 블루프린트를 편집하여 어트리뷰트 세트 타입을 어빌리티 시스템 컴포넌트의 디폴트 시작 데이터로 추가할 수도 있습니다. 세 번째 메서드는 어빌리티 시스템 컴포넌트에 어트리뷰트 세트를 인스턴스화하도록 지시한 다음 자동으로 등록하는 것입니다. 예시는 다음과 같습니다.

    // 이런 코드는 일반적으로 BeginPlay()에 나타나지만,
    // 적절한 어빌리티 시스템 컴포넌트 구하기일 수 있습니다. 다른 액터에 있을 수도 있으므로 GetAbilitySystemComponent를 사용하여 결과가 유효한지 확인하세요.
    AbilitySystemComponent* ASC = GetAbilitySystemComponent();
    
    // AbilitySystemComponent가 유효한지 확인합니다. 실패를 허용할 수 없다면 if() 조건문을 check() 구문으로 대체합니다.
    if (IsValid(ASC))
    {
        // 어빌리티 시스템 컴포넌트에서 UMyAttributeSet를 구합니다. 필요한 경우 어빌리티 시스템 컴포넌트가 UMyAttributeSet를 생성하고 등록할 것입니다.
        AttributeSet = ASC->GetSet<UMyAttributeSet>();
    
    	  // 이제 새 UMyAttributeSet에 대한 포인터가 생겨 나중에 사용할 수 있습니다. 초기화 함수가 있는 경우 여기서 호출하면 좋습니다.
    }
    

<aside> 📌

하나의 어빌리티 시스템 컴포넌트가 다수의 어트리뷰트 세트를 가질 수 있지만, 각 어트리뷰트 세트의 클래스가 모두 달라야 합니다.

</aside>

마지막으로, 어빌리티 시스템 컴포넌트에 없는 게임플레이 어트리뷰트를 수정하는 게임플레이 이펙트를 적용한다면, 어빌리티 시스템 컴포넌트는 일치하는 게임플레이 어트리뷰트를 자동으로 생성합니다. 그러나 이 메서드는 어트리뷰트 세트를 생성하지 않으며, 생성한 게임플레이 어트리뷰트를 기존 어트리뷰트 세트에 추가하지도 않습니다.

  1. 선택 단계로, 게임플레이 어트리뷰트와 상호작용할 기본 헬퍼 함수를 추가할 수 있습니다. 게임플레이 어트리뷰트 자체는 protected나 private 상태로 두고, 상호작용하는 함수를 public으로 하는 것이 좋습니다. 게임플레이 어빌리티 시스템은 일부 디폴트 함수를 구성하는 다음 매크로 세트를 제공합니다.
매크로(파라미터) 생성된 함수의 시그니처 행동/사용
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(UMyAttributeSet, Health) static FGameplayAttribute GetHealth() 스태틱 함수이며, 엔진의 리플렉션 시스템으로부터 FGameplayAttribute 구조체를 반환합니다.
GAMEPLAYATTRIBUTE_VALUE_GETTER(Health) float GetHealth() const 게임플레이 어트리뷰트 'Health'의 현재 값을 반환합니다.
GAMEPLAYATTRIBUTE_VALUE_SETTER(Health) void SetHealth(float NewVal) 게임플레이 어트리뷰트 'Health'의 값을 NewVal 로 설정합니다.
GAMEPLAYATTRIBUTE_VALUE_INITTER(Health) void InitHealth(float NewVal) 게임플레이 어트리뷰트 'Health'의 값을 NewVal 로 초기화합니다.

이를 추가하면 어트리뷰트 세트의 클래스 정의는 다음과 비슷할 것입니다.

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

    protected:
    /** 샘플 어트리뷰트 'Health'*/
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    FGameplayAttributeData Health;

	  //~ ... 여기에 다른 게임플레이 어트리뷰트...

	  public:
    //~ 어트리뷰트 'Health'의 헬퍼 함수
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(UMyAttributeSet, Health);
    GAMEPLAYATTRIBUTE_VALUE_GETTER(Health);
    GAMEPLAYATTRIBUTE_VALUE_SETTER(Health);
    GAMEPLAYATTRIBUTE_VALUE_INITTER(Health);

	  //~ ... 여기에 다른 게임플레이 어트리뷰트의 헬퍼 함수...
};

이러한 헬퍼 함수는 반드시 필요한 것은 아니지만, 모범 사례로 간주됩니다.

이렇게 하면 하나의 게임플레이 어트리뷰트에 대한 기본 어트리뷰트 세트가 만들어집니다. 게임플레이 어트리뷰트의 행동을 제어하는 코드도 구현해야 하며, 그러려면 값들이 어떻게 상호작용해야 하는지, 프로젝트 또는 개발 중인 특정 액터 클래스의 컨텍스트에서 어떤 의미인지 이해해야 합니다. 게임플레이 어트리뷰트 자체에 대한 액세스를 제어하거나 게임플레이 이펙트가 어빌리티 세트 수준에서 작동하는 방식을 유도하여 이 함수 기능을 구축할 수 있습니다.

초기화