Unreal GAS (21) - GameplayAbilities

wnsduf0000·2025년 12월 1일

Unreal_GAS

목록 보기
22/34

2025 / 11 / 02

  • Gameplay Abilities

    • 게임에서 액터가 사용하는 스킬이나 액션 등을 나타내기 위해 사용됨.

    • UGameplayAbility 클래스에서 파생됨.
      어빌리티가 발동 가능한 조건(Cost, Cooldown)과 사용 시의 효과 등을 정의함.

    • 함수가 아니라, 비동기적이며 독립적으로 실행되는 인스턴스 가능한 오브젝트임.
      따라서 원하는 타이밍에 발동되어, 여러 종류의 AbilityTask를 실행할 수 있음.
      AbilityTask는 일정 시간 경과하며 남아있을 수도 있고, 순간적으로 적용될 수도 있음.
      이를 통해 플레이어의 체력을 감소시키거나, SFX를 재생하고 VFX를 표현하는 것 등이 가능함.

      • AbilityTask는 UAbilityTask에서 파생되며, GameplayAbility에 의해 생성될 수도 있고,
        필요하지 않은 경우 사용하지 않을 수도 있음.
        UGameplayTask에서 좀 더 특화된 형태의 클래스임.
      • GameplayAbility가 실행되는 동안 비동기적 처리를 담당하며, 델리게이트에 의해 실행 플로우에 영향을 줄 수 있음.
      • C++에서도 사용 가능하나, AbilityTask 블루프린트 노드로도 사용 가능함.
         
    • GameplayEffect와 마찬가지로, 내부적으로 Replication, Prediction (예측)이 지원됨.

    • GameplayAbility를 사용하기 위해서는 AbilitySystemComponent가 GameplayAbility를 획득 (Grant) 해야 함. GamplayAbility를 획득하면 FGameplayAbilitySpec이 생성되며, 이 Spec을 통해 해당 GameplayAbility에 대한 세부 정보를 얻을 수 있음.

      • GameplayAbility 자체 및 해당 Ability의 레벨, 게임 중에 변경될 수 있는 동적인 데이터 등
      • GameplayAbility의 획득은 서버에서 처리되나, FGameplayAbilitySpec가 소유 클라이언트로 Replicate되어 클라이언트들이 이를 사용할 수 있음.
    • Activation 개념이 담겨 있어, Activate된 이후 자체적으로 종료(End)되거나, 혹은 다른 요소에 의해 중단(Cancel)될 때까지 남아있음.

  • Granting Abilities

    • Aura 프로젝트에서 기본 GameplayAbility 클래스로 사용할 AuraGameplayAbility 클래스를 생성한다. (아직 내용은 아무것도 없음)
    • GameplayAbility는 각 캐릭터들마다 보유하는 것이므로, AuraChracterBase 클래스에 GameplayAbility를 보유할 수 있는 TArray 변수를 하나 추가한다.
      또한 GameplayAbility는 획득(Grant)해야 하는 것이므로, 이를 처리하기 위한 함수 AddCharacterAbilities()도 추가한다.
      ```cpp
      #pragma once
      
      #include "CoreMinimal.h"
      #include "GameFramework/Character.h"
      #include "AbilitySystemInterface.h"
      #include "Interaction/CombatInterface.h"
      #include "AuraCharacterBase.generated.h"
      
      class UAbilitySystemComponent;
      class UAttributeSet;
      class UGameplayEffect;
      class UGameplayAbility;
      
      UCLASS(Abstract)
      class AURA_API AAuraCharacterBase : public ACharacter, public IAbilitySystemInterface, public ICombatInterface
      {
      	GENERATED_BODY()
      
      public:
      	AAuraCharacterBase();
      
      	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
      	UAttributeSet* GetAttributeSet() const { return AttributeSet; } 
      
      protected:
      	virtual void BeginPlay() override;
      
      	virtual void InitAbilityActorInfo();
      
      	void ApplyEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level) const;
      	
      	void InitializeDefaultAttributes() const;
      
      	void AddCharacterAbilities();
      
      	// ...
      
      private:
      	UPROPERTY(EditAnywhere, Category = "Abilities")
      	TArray<TSubclassOf<UGameplayAbility>> StartupAbilities;
      };
      ```
      
      ```cpp
      // AuraCharacterBase.cpp
      void AAuraCharacterBase::AddCharacterAbilities()
      {
      	if (!HasAuthority()) return;
      
      	UAuraAbilitySystemComponent* AuraASC = Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent);
      	AuraASC->AddCharacterAbilities(StartupAbilities);
      }
      ```
      
      - GameplayAbility의 획득은 AbilitySystemComponent에서 처리하나, 해당 처리 자체를 플레이어가 캐릭터를 소유하는 시점에 처리하는 것이 현재로선 가장 바람직해 보이기 때문에, AuraCharacterBase에서 AbilitySystemComponent에 GameplayAbility를 추가하라고 명령하는 함수를 정의하는 것이다.
      GameplayAbility를 획득하는 것은 서버에서 처리하고, FGameplayAbilitySpec이 소유 클라이언트로 Replicate되는 것이므로, 서버가 아니면 실행되지 않도록 HasAuthority()를 통해 서버가 아니면 실행되지 않도록 처리해준다.
          - AbilitySystemComponent의 AddCharacterAbilities()는 AuraCharacterBase에서 선언한 StartupAbilities 배열을 통해 실제로 GameplayAbility를 추가해주는 역할을 하는 별도의 함수다.
          
          ```cpp
          // AuraAbilitySystemComponent.cpp
          void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>> StartupAbilities)
          {
          	for (TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
          	{
          		FGameplayAbilitySpec Spec = FGameplayAbilitySpec(AbilityClass, 1);
          		// GiveAbility(Spec);
          
          		GiveAbilityAndActivateOnce(Spec);
          	}
          }
          ```
          
          - GameplayAbility를 추가하기 위해선 우선 FGameplayAbilitySpec을 생성해야 하며, 생성자에 UGameplayAbility 클래스와 Ability의 레벨을 넘겨주면 된다.
          - GiveAbility()와 GiveAbilityAndActivateOnce()의 차이점은 함수명 그대로, GameplayAbility를 획득하기만 할 것인지, 혹은 획득하고 1회 사용할 것인지의 차이다.
      - AuraPlayerCharacter의 PossessedBy()에서 AddCharacterAbilities()를 호출하여 이를 통해 AuraAbilitySystemComponent의 AddCharacterAbilities()를 호출함으로서 GameplayAbility들이 획득되도록 한다.
          
          ```cpp
          void AAuraPlayerCharacter::PossessedBy(AController* NewController)
          {
          	Super::PossessedBy(NewController);
          
          	/** Init Ability Actor Info for Server */
          	InitAbilityActorInfo();
          
          	AddCharacterAbilities();
          }
          ```
          
    • AuraGameplayAbility를 상속하는 테스트용 블루프린트를 하나 추가해준다.
      해당 블루프린트를 열어보면 이벤트 그래프에 ActivateAbility, OnEndAbility 노드가 기본적으로 존재하는 것을 확인할 수 있다.
      GameplayAbility가 존재하는 것을 확인하기 위해, PrintString을 사용해본다.
      GameplayAbility는 스스로 EndAbility를 통해 효과 종료가 가능하기 때문에, 이를 통해 OnEndAbility도 호출할 수 있다.
  • Settings on Gameplay Abilities

    • GameplayAbility 블루프린트 내의 세팅

      • Tags
    • AbilityTag: 이 GameplayAbility가 갖는 GameplayTag

    • CancelAbilitiesWithTag: 여기에 포함된 GameplayTag를 갖는 다른 GameplayAbility들의 작동을 중단시킴

    • BlockAbilitiesWithTag: 이 GameplayAbility가 작동 중인 동안 여기에 포함된 GameplayTag를 갖는 다른 GameplayAbility의 작동을 방지함.

    • ActivationOwnedTags: 이 GameplayAbility가 작동 중인 동안 이 GameplayAbility를 발동하는 소유 액터에게 추가할 GameplayTag임. AbilitySystemGlobals의 ReplicateActivationOwnedTags가 true인 경우 이 GameplayTag 추가는 Replicate 됨

    • ActivationRequiredTags: 이 GameplayAbility를 사용하는 액터/컴포넌트가 여기에 명시된 모든 GameplayTag를 소유해야만이 이 GameplayAbility를 사용 가능함.

    • ActivationBlockedTags: 이 GameplayAbility를 사용하는 액터/컴포넌트가 여기에 명시된 모든 GameplayTag 중 하나라도 소유한 경우 이 GameplayAbility는 사용 불가능함.

    • SourceRequiredTags: 이 GameplayAbility를 사용하는 액터/컴포넌트가 여기에 명시된 모든 GameplayTag를 소유해야만이 이 GameplayAbility를 사용 가능함.
      (Source와 Activating의 차이점이 무엇인지는 아직 불명확함
      → 예를 들어, 마법사가 파이어볼을 시전한 경우를 생각해보면 될 것 같기도?
      데미지는 파이어볼에서 적용되지만, 이를 시전한 것은 마법사임)

    • SourceBlockedTags: 이 GameplayAbility를 사용하는 액터/컴포넌트가 여기에 명시된 모든 GameplayTag 중 하나라도 소유한 경우 이 GameplayAbility는 사용 불가능함.

    • TargetRequiredTags: 대상 액터/컴포넌트가 여기에 명시된 모든 GameplayTag를 소유해야만이 이 GameplayAbility를 사용 가능함.

    • TargetBlockedTags: 대상 액터/컴포넌트가 여기에 명시된 모든 GameplayTag 중 하나라도 소유한 경우 이 GameplayAbility는 사용 불가능함.

      • Advanced

        • Instancing Policy

          • Instanced Per Actor
            • 단일 인스턴스가 생성되며, 이 GameplayAbility를 사용할 때마다 해당 인스턴스를 재사용함. 단, 매 사용 시마다 관련 변수를 직접 초기화해주어야 함.
            • 동일한 데이터를 지속적으로 갖고 있게끔 할 수 있음.
          • Instanced Per Execution
            • GameplayAbility가 사용될 때마다 새로운 인스턴스를 생성함.
            • 새로운 인스턴스가 매번 생성되므로 성능적으로는 가장 좋지 않은 옵션임.
              단, 매번 변수 등 데이터를 초기화 해 줄 필요는 없음.
          • Non-Instanced
            • CDO(Class Default Object)만 사용 가능하며, 인스턴스가 생성되지 않음.
            • AbilityTask를 위한 델리게이트 적용이나 상태 저장이 불가능함.
              인스턴스가 생성되지 않으므로 성능적으로는 가장 뛰어남.
    • Net Execution Policy

      • Local Only: GameplayAbility가 클라이언트에서만 실행되며, 서버는 이를 모름.
      • Local Predicted: GameplayAbility가 클라이언트에서 실행되고, 이후 서버에서 실행됨. Prediction을 사용하며, 서버 측에서 GameplayAbility의 적용을 롤백할 수 있음.
      • Server Only: 서버 측에서만 실행되고, 클라이언트에서는 실행되지 않음.
      • Server Initiated: 서버 측에서 먼저 실행되고, 이후 클라이언트에서 실행됨.
    • Costs

      • 이 GameplayAbility를 사용하기 위한 코스트 개념을 GameplayEffect 클래스의 형태로 설정할 수 있음.
    • Triggers

      • TriggerSource가 설정된 TriggerTag를 지녔다면, 이 GameplayAbility가 그에 반응하여 작동함.
    • Cooldowns

    • 이 GameplayAbility를 사용하기 위한 쿨타임 개념을 GameplayEffect 클래스의 형태로 설정할 수 있음.

    • 사용하지 않기를 권장하는 옵션

      • Replication Policy: GameplayAbility는 자동적으로 Replicate되므로 사용하지 않음.
      • Server Respects Remove Ability Cancellation: 서버 측에서 주도하는 것이 좋음.
      • Replicate Input Directly: 에픽게임즈에서 권장하지 않음.
profile
저는 게임 개발자로 일하고 싶어요

0개의 댓글