본문 바로가기
Unreal 게임 개발/Unreal 강의 개인 정리

GA에서 AT 사용 방법 (+BP) - GAS

by daisy0461 2025. 8. 20.

AbilityTask 제작 규칙

  • AT는 UAbilityTask를 상속받아 제작한다.
  • 일반적으로 AT 인스턴스를 생성해 반환하는 Static함수를 선언하여 구현한다.
  • AT가 종료되면 GA에 알려줄 Delegate를 선언한다.
  • 시작과 종료 처리를 위해 Activate와 OnDestroy함수를 재정의해 구현한다.
  • 일정 시간이 지난 후 AT를 종료하고 싶으면 활성화 시 SetWaitingOnAvatar함수를 호출하여
    Waiting상태로 설정한다.
  • Tick을 활성화하고 싶으면 bTickingTask값을 true로 설정한다.
  • AT가 종료되면 Delegate를 Broadcast하여 AT에게 종료됨을 알린다.

 

GA와 AT 사이 실행 흐름

  1. GA는 사용할 AT를 Static함수를 호출하여 생성.
  2. AT에서 객체 초기 변수 설정 및 Delegate 구독.
  3. GA가 ReadyForActivation을 사용하여 AT 활성화. - > AT의 Activate함수 호출
  4. 대기 상태 설정(SetWaitingOnAvatar)설정이 있으면 끝날 때 까지 동작을 함.
  5. Task가 종료가 되면 Delegate를 통해 GA에 Task가 종료됨을 알림.
  6. GA는 Task종료를 받고 EndAbility 호

 

점프 GA와 AT

Unreal에서 기본으로 제공하는 GameplayAbility_CharacterJump는 상태가 보존되지 않아서 새로 만들어보자.

AbilityTask C++ 제작

AT는 위 사진과 같이 AbilityTask를 상속받아서 제작하면 된다.

제작한 AT Class는 아래와 같다.

#include "GA/AT/ABAT_JumpAndWaitForLanding.h"
#include "GameFramework/Character.h"

UABAT_JumpAndWaitForLanding::UABAT_JumpAndWaitForLanding()
{
}

UABAT_JumpAndWaitForLanding* UABAT_JumpAndWaitForLanding::CreateTask(UGameplayAbility* OwningAbility)
{
	//해당 AT에 대한 Instance가 생성된다. OwningAbility를 Outer로 지정한다.
	UABAT_JumpAndWaitForLanding* NewTask = NewAbilityTask<UABAT_JumpAndWaitForLanding>(OwningAbility);
	//이후 추가 파라미터가  있다면 변수 설정을 아래에서하면 된다.

	return NewTask;
}

void UABAT_JumpAndWaitForLanding::Activate()
{
	Super::Activate();

	//GetAvatarActor를 들어가보면 TaskOwner(GA)의 AvatarActor를 들고오는 동작이다.
	ACharacter* Character = CastChecked<ACharacter>(GetAvatarActor());
	//캐릭터에서 기본으로 제공하는 착지 Delegate를 사용하여 땅에 착지하였는지 확인.
	Character->LandedDelegate.AddDynamic(this, &UABAT_JumpAndWaitForLanding::OnLandedCallback);
	Character->Jump();

	//점프의 경우 언제 끝날지 판단하기 어렵기에 AT의 상태를 Waiting으로 설정
    //호출하지 않으면 바로 Task가 종료된다.
	SetWaitingOnAvatar();
}

void UABAT_JumpAndWaitForLanding::OnDestroy(bool AbilityEnded)
{
	ACharacter* Character = CastChecked<ACharacter>(GetAvatarActor());
	Character->LandedDelegate.RemoveDynamic(this, &UABAT_JumpAndWaitForLanding::OnLandedCallback);
	Super::OnDestroy(AbilityEnded);
}

void UABAT_JumpAndWaitForLanding::OnLandedCallback(const FHitResult& Hit)
{
	//ShouldBroadcastAbilityTaskDelegates는 Task가 아직 유효하고, Delegate 호출해도 안전한지 판단하는데 사용된다.
	//이미 Task가 종료, 캔슬, PandingKill 상태일 때 Broadcast하면 크래쉬나 예상 못한 상황이 발생할 수 있기 때문이다.
	if (ShouldBroadcastAbilityTaskDelegates())
	{
    		//Task 종료
		OnComplete.Broadcast();
	}
}

 

Jump GA는 아래와 같다.

// Fill out your copyright notice in the Description page of Project Settings.


#include "GA/ABGA_Jump.h"
#include "GA/AT/ABAT_JumpAndWaitForLanding.h"
#include "GameFramework/Character.h"

UABGA_Jump::UABGA_Jump()
{
	//이렇게 해야 상태 보존 가능.
	InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
}

bool UABGA_Jump::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
{
	bool bResult = Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags);
	if (!bResult) return false;

	const ACharacter* Character = Cast<ACharacter>(ActorInfo->AvatarActor.Get());

	return (Character && Character->CanJump());
}

void UABGA_Jump::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
	//Task 생성, Delegate 구독 및 실행
	UABAT_JumpAndWaitForLanding* JumpAndWaitingForLandingTask = UABAT_JumpAndWaitForLanding::CreateTask(this);
	JumpAndWaitingForLandingTask->OnComplete.AddDynamic(this, &UABGA_Jump::OnLandedCallback);
	JumpAndWaitingForLandingTask->ReadyForActivation();
}

void UABGA_Jump::InputReleased(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
	Super::InputReleased(Handle, ActorInfo, ActivationInfo);

	ACharacter* Character = CastChecked<ACharacter>(ActorInfo->AvatarActor.Get());
	Character->StopJumping();
}

void UABGA_Jump::OnLandedCallback()
{
	bool bReplicatedEndAbility = true;
	bool bWasCancelled = false;

	EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
}

위 두 코드에 주석을 읽으면 어떤 동작인지 쉽게 알 수 있을 것이다.

 

간단한 흐름이다.

  1. JumpGA Activate 시 Task생성, Task의 완료 Delegate 구독, Task 실행.
  2. Task에서 점프 실행 및 착지 시 OnLandCallback 호출
  3. OnLandCallback에서 Task 종료 및 Delegate Broadcast로 JumpGA의 OnLandCallback 실행.
  4. Jump GA의 EndAbility 호출.

 

Blueprint에서 AT 호출 방법

public:
	UABAT_JumpAndWaitForLanding();

	//일반적으로 자기를 소유하고 있는 GA를 기본 파라미터로 넣어준다.
	//추가적으로 해당 클래스의 변수등을 설정하고 싶다면 다른 파라미터를 추가하여 사용 가능하다.
	UFUNCTION(BlueprintCallable, Category = "Ability|Task", meta = (DisplayName = "JumpAndWaitForLanding", HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE"))
	static UABAT_JumpAndWaitForLanding* CreateTask(UGameplayAbility* OwningAbility);
	
	virtual void Activate() override;
	virtual void OnDestroy(bool AbilityEnded) override;

	UPROPERTY(BlueprintAssignable)
	FJumpAndWaitForLandingDelegate OnComplete;

위에 제작했던 JumpAndWaitForLanding AT를 그대로 들고와서

static 함수를 BlueprintCallable로
종료 시 호출될 함수를 BlueprintAssignable로 넣어주면 된다.

그 외에 다른 Category나 DisplayName 등등 은 필수가 아니지만 지정해주면 더 쉽고 직관적으로 작업이 가능하다.

위 사진이 JumpAndWaitForLanding Blueprint Node 연결 사진이다.

cpp와 h파일을 동일하게 넣고 실행해보면 cpp로만 했을 때의 동작과 동일하게 동작하는 것을 확인할 수 있다.

 

 

추가적으로

현재는 점프 중에 공격이 가능했다. 이것을 Block하는 방법도 GAS에선 간단하다.

Attack GA에서 ActivationBlockedTags에 점프를 하고 있다는 Tag를 넣으면 Jump 중엔 공격이 불가능하게 Block된다.