• 다른 GAS 액터의 상황을 확인할 수 있는 디버그 시스템 설정 방법의 학습
  • 기본 캐릭터 어트리뷰트 설정 방법의 학습
  • 공격 대상의 어트리뷰트 값을 변경하는 방법의 학습   
  • 특정 어트리뷰트 변경 시 사전, 사후 점검하는 방법의 학습 

 

인프런 이득우님의 '언리얼 프로그래밍 Part4 - 게임플레이 어빌리티 시스템' 강의를 참고하였습니다. 
😎 [이득우의 언리얼 프로그래밍 Part4 - 게임플레이 어빌리티 시스템] 강의 들으러 가기!

 

 

 

목차

     

     


     

     

    캐릭터 어트리뷰트 설정 방향

     


     

     

    캐릭터 어트리뷰트 설정 기획

     

    • 캐릭터에 설정할 어트리뷰트 목록
    • 기본 어트리뷰트
      • 체력 Health
      • 일반 공격 길이 AttackRange 
      • 일반 공격 변경 AttackRadius
      • 일반 공격력 AttackRate
    • 최대값 어트리뷰트
      • 최대 체력 MaxHealth
      • 최대 일반 공격 길이 MaxAttackRange
      • 최대 일반 공격 반경 MaxAttackRadius
      • 최대 공격력 MaxAttackRate

     

     

    핵심 구성요소

     

     

    ASC를 중심으로 어트리뷰트를 설정하게 되면 이 둘이 서로 연동하게 된다.

     

     

    Attribute Set 바탕으로 Gamplay Ability(GA)Ability Task(AT)에 영향을 주는 형태로 작업


     

     

     

    AttributeSet 활용한 GAS NPC의 설정

     


     

     

    ABGASCharacterNonPlayer 생성

     

    ABCharacterNonPlayer - ABGASCharacterNonPlayer 생성

     

     

    ABGASCharacterNonPlayer.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Character/ABCharacterNonPlayer.h"
    #include "AbilitySystemInterface.h"
    #include "ABGASCharacterNonPlayer.generated.h"
    
    UCLASS()
    class ARENABATTLEGAS_API AABGASCharacterNonPlayer : public AABCharacterNonPlayer, public IAbilitySystemInterface
    {
    	GENERATED_BODY()
    	
    public:
    	AABGASCharacterNonPlayer();
    	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    	virtual void PossessedBy(AController* NewController) override; // AIController가 이 NPCController를 장악할 때 그 타이밍에 ASC를 초기화
    
    protected:
    	UPROPERTY(EditAnywhere, Category = GAS)
    	TObjectPtr<class UAbilitySystemComponent> ASC;
    
    	UPROPERTY()
    	TObjectPtr<class UABCharacterAttributeSet> AttributeSet;
    };

     

     

     

    ABGASCharacterNonPlayer.cpp

    더보기
    #include "Character/ABGASCharacterNonPlayer.h"
    #include "AbilitySystemComponent.h"
    #include "Attribute/ABCharacterAttributeSet.h"
    
    AABGASCharacterNonPlayer::AABGASCharacterNonPlayer()
    {
    	ASC = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC"));
    	AttributeSet = CreateDefaultSubobject<UABCharacterAttributeSet>(TEXT("AttributeSet"));
    }
    
    UAbilitySystemComponent* AABGASCharacterNonPlayer::GetAbilitySystemComponent() const
    {
    	return ASC;
    }
    
    void AABGASCharacterNonPlayer::PossessedBy(AController* NewController)
    {
    	Super::PossessedBy(NewController);
    
    	ASC->InitAbilityActorInfo(this, this);
    }

     

     

     


     

     

    어트리뷰트 세트 Attribute Set

     

    Attribute Set

    • 단일 어트리뷰트 데이터인 GameplayAttributeData의 묶음
    • GameplayAttributeData는 하나의 값이 아닌 두 가지 값이 구성되어 있음 
      • BaseValue기본값. 영구히 적용되는 고정 스탯 값을 관리하는데 사용
      • CurrentValue변동값. 버프(Buff) 등으로 임시적으로 변동된 값을 관리하는데 사용
    • AttributeSet의 주요 함수
      • PreAttributeChange  :  어트리뷰트 변경 전에 호출
        • virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
        • 두번째 인자가 레퍼런스(&)로 들어온다.
        • 바꾸기 전에 들어온 값이 마음에 안 드는 경우, 다시 설정할 수 있게 하는 함수다.
      • PostAttributeChange :  어트리뷰트 변경 후에 호출
        • PreAttributeChange와 달리 값을 변경할 수 없다.
        • 로그를 남길 때 자주 사용하는 함수다.
      • PreGameplayEffectExecute :  게임플레이 이펙트 적용 전에 호출
      • PostGameplayEffectExecute :  게임플레이 이펙트 적용 후에호출  
    • AttributeSet 접근자 매크로
      • 많이 수행되는 기능에 대해 매크로를 만들어 제공함
    • ASC는 초기화될 때 같은 액터에 있는 UAttributeSet 타입 객체를 찾아서 등록함
      • 사용자가 별도로 AttributeSet를 AttributeSystemComponent(ASC)에 수동으로 등록할 필요 없다.
      • ASC는 초기화될 때 자기를 부모로 가지는 OwnerActor에 있는 AttributeSet 타입 객체를 찾아서 자동으로 등록한다.

    아래 예제에서는 BaseValue만 사용했다. 

     

     

     

    ※ AttributeSet.h에 설명된 ATTRIBUTE_ACCESSORS 사용법

    • GAMEPLAYATTRIBUTE_PROPERTY_GETTER는 AttributeSet나 Attribute를 나타내는 클래스에 등록된 프로퍼티를 가져오는 매크로다.
    • GAMEPLAYATTRIBUTE_VALUE_GETTER는 CurrentValue를 가져오는 매크로다. 
    • GAMEPLAYATTRIBUTE_VALUE_SETTER는 BaseValue 를 바꿔주는 매크로다. 
    • GAMEPLAYATTRIBUTE_VALUE_INITTER는 BaseValueCurrentValue를 같은 값으로 지정해주는 매크로다.

     

     

     

    ※ ASC가 UAttributeSet 타입 객체를 찾는 로직
    - AbilitySystemComponent.h + AbilitySystemComponent_Abilities.cpp

    • AbilitySystemComponent.h의 함수 virtual void IntializeComponent override;
    • AbilitySystemComponent_Abilities.cpp에서 해당 함수를 재정의한다.
      • TArray<UObject*> ChildObjects;
        GetObjectsWithOuter(Owner, ChildObjects, false, RF_NoFlags, EInternalObjectFlags::Garbage); 
      • Owner가 가지고 있는 자식 오브젝트(= ChildObjects)를 TArray로 가져온 후  자식 오브젝트 중에 형이 AttributeSet 얘가 있으면 SpawnedAttributes라는 어트리뷰트 목에 AddUnique로 추가한다.

     

    AbilitySystemComponent.h

     

    AbilitySystemComponent_Abilities.cpp


     

     

    ABCharacterAttributeSet 생성

     

    AttributeSet - ABCharacterAttributeSet 생성

     

     

    ABCharacterAttributeSet.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "AttributeSet.h"
    #include "AbilitySystemComponent.h"
    #include "ABCharacterAttributeSet.generated.h"
    
    #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
    	GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    	GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    	GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    	GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
    
    UCLASS()
    class ARENABATTLEGAS_API UABCharacterAttributeSet : public UAttributeSet
    {
    	GENERATED_BODY()
    	
    public:
    	UABCharacterAttributeSet();
    
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, AttackRange);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, MaxAttackRange);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, AttackRadius);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, MaxAttackRadius);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, AttackRate);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, MaxAttackRate);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, Health);
    	ATTRIBUTE_ACCESSORS(UABCharacterAttributeSet, MaxHealth);
    
    	virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
    	virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
    
    protected:
    	UPROPERTY(BlueprintReadOnly, Category="Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData AttackRange;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData MaxAttackRange;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData AttackRadius;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData MaxAttackRadius;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData AttackRate;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData MaxAttackRate;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Health", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData Health;
    
    	UPROPERTY(BlueprintReadOnly, Category = "Attack", Meta = (AllowPrivateAccess = true))
    	FGameplayAttributeData MaxHealth;
    };

     

     

     

    ABCharacterAttributeSet.cpp

    더보기
    #include "Attribute/ABCharacterAttributeSet.h"
    #include "ArenaBattleGAS.h"
    
    UABCharacterAttributeSet::UABCharacterAttributeSet() :
    	AttackRange(100.0f),
    	AttackRadius(50.f),
    	AttackRate(30.0f),
    	MaxAttackRange(300.0f),
    	MaxAttackRadius(150.0f),
    	MaxAttackRate(100.0f),
    	MaxHealth(100.0f)
    {
    	InitHealth(GetMaxHealth());
    }
    
    void UABCharacterAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
    {
    	if (Attribute == GetHealthAttribute())
    	{
    		NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxHealth());
    	}
    }
    
    void UABCharacterAttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
    {
    	if (Attribute == GetHealthAttribute())
    	{
    		ABGAS_LOG(LogABGAS, Log, TEXT("Health : %f -> %f"), OldValue, NewValue);
    	}
    }

     


     

     

    ABGASPlayerState - ABCharacterAttributeSet 포인터 변수 추가 

     

    ABGASPlayerState.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/PlayerState.h"
    #include "AbilitySystemInterface.h"
    #include "ABGASPlayerState.generated.h"
    
    UCLASS()
    class ARENABATTLEGAS_API AABGASPlayerState : public APlayerState, public IAbilitySystemInterface
    {
    	GENERATED_BODY()
    	
    public:
    	AABGASPlayerState();
    	
    	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
    protected:
    	UPROPERTY(EditAnywhere, Category = GAS)
    	TObjectPtr<class UAbilitySystemComponent> ASC;
    
    	UPROPERTY()
    	TObjectPtr<class UABCharacterAttributeSet> AttributeSet;
    };

    변수 추가

    • UPROPERTY()
      TObjectPtr<class UABCharacterAttributeSet> AttributeSet;

     

     

    ABGASPlayerState.cpp

    더보기
    #include "Player/ABGASPlayerState.h"
    #include "AbilitySystemComponent.h"
    #include "Attribute/ABCharacterAttributeSet.h"
    
    AABGASPlayerState::AABGASPlayerState()
    {
    	ASC = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC"));
    	//ASC->SetIsReplicated(true);
    	AttributeSet = CreateDefaultSubobject<UABCharacterAttributeSet>(TEXT("AttributeSet"));
    }
    
    UAbilitySystemComponent* AABGASPlayerState::GetAbilitySystemComponent() const
    {
    	return ASC;
    }

    AABGASPlayerState::AABGASPlayerState()

    • ASC가 AttributeSet를 직접 관리한다.
    • AttributeSet을 수동으로 ASC에 추가한 적이 없다. 하지만 ASC는 초기화될 때 자기를 부모로 가지는 OwnerActor에 있는 AttributeSet 타입 객체를 찾아서 자동으로 등록한다.

     

     

    ABTA_Trace

     

    ABTA_Trace.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Abilities/GameplayAbilityTargetActor.h"
    #include "ABTA_Trace.generated.h"
    
    UCLASS()
    class ARENABATTLEGAS_API AABTA_Trace : public AGameplayAbilityTargetActor
    {
    	GENERATED_BODY()
    	
    public:
    	AABTA_Trace();
    
    	virtual void StartTargeting(UGameplayAbility* Ability) override;
    
    	virtual void ConfirmTargetingAndContinue() override;
    	void SetShowDebug(bool InShowDebug) { bShowDebug = InShowDebug; }
    
    protected:
    	virtual FGameplayAbilityTargetDataHandle MakeTargetData() const;
    
    	bool bShowDebug = false;
    };

    변경사항 없음

     

     

    ABTA_Trace.cpp

    더보기
    #include "GA/TA/ABTA_Trace.h"
    #include "Abilities/GameplayAbility.h"
    #include "GameFramework/Character.h"
    #include "Components/CapsuleComponent.h"
    #include "Physics/ABCollision.h"
    #include "DrawDebugHelpers.h"
    #include "AbilitySystemComponent.h"
    #include "Attribute/ABCharacterAttributeSet.h"
    #include "AbilitySystemBlueprintLibrary.h"
    #include "ArenaBattleGAS.h"
    
    AABTA_Trace::AABTA_Trace()
    {
    }
    
    void AABTA_Trace::StartTargeting(UGameplayAbility* Ability)
    {
    	Super::StartTargeting(Ability);
    
    	SourceActor = Ability->GetCurrentActorInfo()->AvatarActor.Get();
    }
    
    void AABTA_Trace::ConfirmTargetingAndContinue()
    {
    	if (SourceActor)
    	{
    		FGameplayAbilityTargetDataHandle DataHandle = MakeTargetData();
    		TargetDataReadyDelegate.Broadcast(DataHandle);
    	}
    }
    
    FGameplayAbilityTargetDataHandle AABTA_Trace::MakeTargetData() const
    {
    	ACharacter* Character = CastChecked<ACharacter>(SourceActor);
    
    	UAbilitySystemComponent* ASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(SourceActor);
    	if (!ASC)
    	{
    		ABGAS_LOG(LogABGAS, Error, TEXT("ASC not found!"));
    		return FGameplayAbilityTargetDataHandle();
    	}
    
    	const UABCharacterAttributeSet* AttributeSet = ASC->GetSet<UABCharacterAttributeSet>();
    	if (!AttributeSet)
    	{
    		ABGAS_LOG(LogABGAS, Error, TEXT("ABCharacterAttributeSet not found!"));
    		return FGameplayAbilityTargetDataHandle();
    	}
    
    	FHitResult OutHitResult;
    	const float AttackRange = AttributeSet->GetAttackRange();
    	const float AttackRadius = AttributeSet->GetAttackRadius(); // GetAttackRadius()는 GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) 매크로 내에 구현되었다
    
    	FCollisionQueryParams Params(SCENE_QUERY_STAT(UABTA_Trace), false, Character);
    	const FVector Forward = Character->GetActorForwardVector();
    	const FVector Start = Character->GetActorLocation() + Forward * Character->GetCapsuleComponent()->GetScaledCapsuleRadius();
    	const FVector End = Start + Forward * AttackRange;
    
    	bool HitDetected = GetWorld()->SweepSingleByChannel(OutHitResult, Start, End, FQuat::Identity, CCHANNEL_ABACTION, FCollisionShape::MakeSphere(AttackRadius), Params);
    
    	FGameplayAbilityTargetDataHandle DataHandle;
    	if (HitDetected)
    	{
    		FGameplayAbilityTargetData_SingleTargetHit* TargetData = new FGameplayAbilityTargetData_SingleTargetHit(OutHitResult);
    		DataHandle.Add(TargetData);
    	}
    
    #if ENABLE_DRAW_DEBUG
    
    	if (bShowDebug)
    	{
    		FVector CapsuleOrigin = Start + (End - Start) * 0.5f;
    		float CapsuleHalfHeight = AttackRange * 0.5f;
    		FColor DrawColor = HitDetected ? FColor::Green : FColor::Red;
    		DrawDebugCapsule(GetWorld(), CapsuleOrigin, CapsuleHalfHeight, AttackRadius, FRotationMatrix::MakeFromZ(Forward).ToQuat(), DrawColor, false, 5.0f);
    	}
    
    #endif
    
    	return DataHandle;
    }

    FGameplayAbilityTargetDataHandle AABTA_Trace::MakeTargetData() const

     


     

     

    ABGA_AttackHitCheck

     

    ABGA_AttackHitCheck.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Abilities/GameplayAbility.h"
    #include "ABGA_AttackHitCheck.generated.h"
    
    UCLASS()
    class ARENABATTLEGAS_API UABGA_AttackHitCheck : public UGameplayAbility
    {
    	GENERATED_BODY()
    	
    public:
    	UABGA_AttackHitCheck();
    
    	virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
    
    protected:
    
    	UFUNCTION()
    	void OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle);
    };

     

     

    ABGA_AttackHitCheck.cpp

    더보기
    #include "GA/ABGA_AttackHitCheck.h"
    #include "ArenaBattleGAS.h"
    #include "AbilitySystemBlueprintLibrary.h"
    #include "GA/AT/ABAT_Trace.h"
    #include "GA/TA/ABTA_Trace.h"
    #include "Attribute/ABCharacterAttributeSet.h"
    #include "ArenaBattleGAS.h"
    
    UABGA_AttackHitCheck::UABGA_AttackHitCheck()
    {
    	InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
    }
    
    void UABGA_AttackHitCheck::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
    {
    	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
    
    	UABAT_Trace* AttackTraceTask = UABAT_Trace::CreateTask(this, AABTA_Trace::StaticClass());
    	AttackTraceTask->OnComplete.AddDynamic(this, &UABGA_AttackHitCheck::OnTraceResultCallback);
    	AttackTraceTask->ReadyForActivation();
    }
    
    void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
    {
    	// TargetDataHandle는 배열로 들어오기 때문에 0번 인덱스(=첫번째 데이터)에 이것이 있는지 확인
    	if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0))
    	{
    		FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0);
    		ABGAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *(HitResult.GetActor()->GetName()));
    
    		UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked();
    		UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitResult.GetActor());
    		if (!SourceASC || !TargetASC)
    		{
    			ABGAS_LOG(LogABGAS, Error, TEXT("ASC not found!"));
    			return;
    		}
    
    		const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>();
    		UABCharacterAttributeSet* TargetAttribute = const_cast<UABCharacterAttributeSet*>(TargetASC->GetSet<UABCharacterAttributeSet>());
    		if (!SourceAttribute || !TargetAttribute)
    		{
    			ABGAS_LOG(LogABGAS, Error, TEXT("ASC not found!"));
    			return;
    		}
    
    		const float AttackDamage = SourceAttribute->GetAttackRate();
    		TargetAttribute->SetHealth(TargetAttribute->GetHealth() - AttackDamage);
    
    	}
    
    	bool bReplicatedEndAbility = true;
    	bool bWasCancelled = false;
    	EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
    }

    void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)

    • UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked();
      • 소스에서 타겟으로 넘겨야 하므로 체크로 확인한 AbilitySystemComponent를 가져옴
    • UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitResult.GetActor());
      • 물리 판정을 감지한 타겟 액터
    • const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>();
    • UABCharacterAttributeSet* TargetAttribute = const_cast<UABCharacterAttributeSet*>(TargetASC->GetSet<UABCharacterAttributeSet>());
    • 데미지 전달 로직
      const float AttackDamage = SourceAttribute->GetAttackRate();
      TargetAttribute->SetHealth(TargetAttribute->GetHealth() - AttackDamage);

     

     

     

     

    DefaultGame.ini - NonPlayer도 debug abilitysystem에 보이도록 수정

     

    DefaultGame.ini

    더보기
    [/Script/EngineSettings.GeneralProjectSettings]
    ProjectID=5E31F5844E5898517BA834A3EF9332C9
    
    [/Script/Engine.AssetManagerSettings]
    -PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass=/Script/Engine.World,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
    -PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass=/Script/Engine.PrimaryAssetLabel,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
    +PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass="/Script/Engine.World",bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
    +PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass="/Script/Engine.PrimaryAssetLabel",bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
    bOnlyCookProductionAssets=False
    bShouldManagerDetermineTypeAndName=False
    bShouldGuessTypeAndNameInEditor=True
    bShouldAcquireMissingChunksOnLoad=False
    bShouldWarnAboutInvalidAssets=True
    MetaDataTagsForAssetRegistry=()
    
    [/Script/GameplayAbilities.AbilitySystemGlobals]
    bUseDebugTargetFromHud=True

    코드 추가

    • [/Script/GameplayAbilities.AbilitySystemGlobals]
      bUseDebugTargetFromHud=True

     

     

    실행화면

     

    좌측상단의 Health가 줄어드는것을 확인할 수 있다.

     


     

     

    정리

     

    • GAS NPC 제작과 캐릭터에 어트리뷰트를 부여하는 방법의 이해
    • ASC에서 AttributeSet을 초기화하는 과정의 학습
    • NPC의 어트리뷰트와 태그 값을 확인할 수 있는 디버그 시스템의 추가 설정
    • ASC와 매크로를 사용해 어트리뷰트 값을 가져오고, 변경하는 기능의 구현 
    • 변경되는 어트리뷰트 값의 검증 방법의 학습