어빌리티 시스템 컴포넌트(ASC, Ability System Component)

게임플레이 어빌리티 및 다양한 작업을 관리하고 처리하는 중앙 처리 장치

액터에 단 하나만 부착할 수 있고, 게임플레이 어빌리티를 발동시킬 수 있음

ASC를 부착한 액터 사이에 GAS 시스템의 상호작용이 가능

 

게임플레이 어빌리티(GA, GamePlay Ability)

ASC에 등록되어 발동시킬 수 있는 액션(공격, 마법 등 간단한 액션 뿐만아니라 복잡한 액션) 명령

 

GA의 발동 과정

  1. ASC에 어빌리티를 등록 : ASC의 GiveAbility 함수에 발동할 GA의 타입을 전달
    발동할 GA 타입 정보를 게임플레이 어빌리티 스펙이라고 함
  2. ASC에게 어빌리티를 발동하려고 명령 : ASC의 TryActivateAbility 함수에 발동할 GA의 타입을 전달
    ASC에 등록된 타입이면 GA의 인스턴스가 생성됨
  3. 발동된 GA에는 발동한 액터와 실행정보가 기록됨
    SpecHandle : 발동된 어빌리티에 대한 핸들
    ActorInfo : 어빌리티 소유자와 아바타(비주얼만 수행하는 액터) 정보
    ActivationInfo : 발동 방식에 대한 정보

GA의 주요 함수

CanActivateAbility : 어빌리티가 발동할 수 있는지 체크하는 함수

ActivateAbility : 어빌리티가 발동될 때 호출

CancelAbility : 어빌리티가 취소될 때 호출

EndAbility : 스스로 어빌리티를 마무리할 때 호출

 

AABGASFountain::AABGASFountain()
{
	AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
	RotatingMovement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("RotateMovement"));
	ActionPeriod = 3.0f;
}

void AABGASFountain::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	// 액터가 초기화될 때 반드시 InitAbilityActorInfo 함수를 호출하여 AbilitySystemComponent를 초기화해야 함
	AbilitySystemComponent->InitAbilityActorInfo(this, this);

	// 처음부터 인스턴스를 생성하면 부하가 클 수 있기 때문에 기본적인 정보만 보유
	FGameplayAbilitySpec RotateSkillSpec(UABGA_Rotate::StaticClass());
	AbilitySystemComponent->GiveAbility(RotateSkillSpec);

	RotatingMovement->bAutoActivate = false;
	RotatingMovement->Deactivate();
}

void AABGASFountain::BeginPlay()
{
	Super::BeginPlay();

	GetWorld()->GetTimerManager().SetTimer(ActionTimer, this, &AABGASFountain::TimerAction, ActionPeriod, true, 0.0f);
}

void AABGASFountain::TimerAction()
{
	ABGAS_LOG(LogABGAS, Log, TEXT("Begin"));

	FGameplayAbilitySpec* RotateSpec = AbilitySystemComponent->FindAbilitySpecFromClass(UABGA_Rotate::StaticClass());
	if (RotateSpec == nullptr)
	{
		ABGAS_LOG(LogABGAS, Log, TEXT("Rotate Spec Not Found"));
		return;
	}

	if (RotateSpec->IsActive() == false)
	{
		AbilitySystemComponent->TryActivateAbility(RotateSpec->Handle);
	}
	else
	{
		AbilitySystemComponent->CancelAbilityHandle(RotateSpec->Handle);
	}
}

 

void UABGA_Rotate::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);

	if (AActor* AvatarActor = ActorInfo->AvatarActor.Get())
	{
		if (UActorComponent* RotatingMovement = AvatarActor->GetComponentByClass(URotatingMovementComponent::StaticClass()))
		{
			RotatingMovement->Activate(true);
		}
	}
}

void UABGA_Rotate::CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility)
{
	Super::CancelAbility(Handle, ActorInfo, ActivationInfo, bReplicateCancelAbility);
	
	if (AActor* AvatarActor = ActorInfo->AvatarActor.Get())
	{
		if (UActorComponent* RotatingMovement = AvatarActor->GetComponentByClass(URotatingMovementComponent::StaticClass()))
		{
			RotatingMovement->Deactivate();
		}
	}
}

 

게임플레이 태그

FName으로 관리되는 경량의 표식 데이터(액터나 컴포넌트에 지정했던 태그와는 다름)

 

프로젝트 설정에서 별도로 게임플레이 태그를 생성하고 관리할 수 있음

결과는 DefaultGamePlayTags.ini 파일에 저장됨

 

계층 구조로 구성되어 있어 체계적인 관리 가능

Actor.Action.Rotate : 행동에 대한 태그

Actor.State.IsRotating : 상태에 대한 태그

 

게임플레이 태그들의 저장소 : GamePlayTagContainer

계층구조를 지원하는 검색 기능 제공

HasTagExact : 완전히 일치하는지 체크 : 컨테이너에 A.1 태그가 있는 상황에서 A로 찾으면 false

HasAny : 컨테이너에 A.1 태그가 있는 상황에서 A와 B로 찾으면 true

HasAnyExact : 컨테이너에 A.1 태그가 있는 상황에서 A와 B로 찾으면 false

HasAll : 컨테이너에 A.1, B.1 태그가 있는 상황에서 A와 B로 찾으면 true

HasAllExact : 컨테이너 A.1, B.1 태그가 있는 상황에서 A와 B로 찾으면 false

 

GAS와 독립적으로 사용 가능

 

게임플레이 어빌리티에 부착한 태그

TagContainer에 Tag를 부착하면 게임플레이 어빌리티를 대표하는 태그가 됨

 

게임플레이 어빌리티에 대한 다양한 실행 조건의 설정

태그로 어빌리티 취소 : CancelAbilitiesWithTag

태그로 어빌리티 차단 : BlockAbilitiesWithTag

어빌리티 실행시 태그 설정 : ActivationOwnedtags

태그가 있어야만 어빌리티 실행 : ActivationRequiredTags

태그가 있으면 어빌리티 실행 차단 : ActivationBlockedTags

시전자가 태그가 있어야 어빌리티 실행 : SourceRequiredTags

시전자에 태그가 있으면 어빌리티 차단 : SourceBlockedTags

시전 대상에 태그가 있어야 어빌리티 실행 : TargetRequiredTags

시전 대상에 태그가 있으면 어빌리티 차단 : TargetBlockedTags

 

블루프린트와 조합하여 특정 게임플레이 어빌리티에 대한 의존성을 없애고 게임플레이 태그를 중심으로 게임 로직을 전개 가능

 

태그를 사용해 헤더의 의존성을 줄일 수 있음

 

게임플레이 어빌리티를 만들고 태그만 필요할 때 잘 설정하면 어빌리티를 변경해도 시스템에 영향이 없기 때문에 GAS 시스템이 가지는 유연성과 확장성이 높음

 

UABGA_Rotate::UABGA_Rotate() {
	AbilityTags.AddTag(ABTAG_ACTOR_ROTATE);
	ActivationOwnedTags.AddTag(ABTAG_ACTOR_ISROTATING);
}

 

void AABGASFountain::PostInitializeComponents()
{
	// 처음부터 인스턴스를 생성하면 부하가 클 수 있기 때문에 기본적인 정보만 보유
	for (const TSubclassOf<UGameplayAbility>& Ability : Abilities)
	{
		FGameplayAbilitySpec AbilitySpec(Ability);
		AbilitySystemComponent->GiveAbility(AbilitySpec);
	}
}

void AABGASFountain::TimerAction()
{
	ABGAS_LOG(LogABGAS, Log, TEXT("Begin"));

	FGameplayTagContainer TargetTag(ABTAG_ACTOR_ROTATE);

	if (AbilitySystemComponent->HasMatchingGameplayTag(ABTAG_ACTOR_ISROTATING) == false)
	{
		AbilitySystemComponent->TryActivateAbilitiesByTag(TargetTag);
	}
	else
	{
		AbilitySystemComponent->CancelAbilities(&TargetTag);
	}
}

+ Recent posts

목차