일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- dirty cow
- stride
- gas
- 유스케이스
- pdlc
- frequency-domain spectrum analysis
- Rr
- 운영체제
- DSP
- Double free
- 언리얼 엔진
- ability task
- DP
- dtft
- MLFQ
- ret2libc
- Race condition
- 메카님
- 유니티
- CTF
- MAC
- sampling theory
- linear difference equation
- 게임개발
- TSet
- AINCAA
- 언리얼엔진
- 게임 개발
- Unreal Engine
- Security
- Today
- Total
다양한 기록
[Unreal GAS] GAS의 시작 본문
어빌리티 시스템으로 회전하는 분수대 구현하기
1. 액터에 넣기
2. GAS로 구현
3. GAS에 게임플레이 태그를 부여해 구현
1. 액터에 넣기
// Fill out your copyright notice in the Description page of Project Settings.
#include "Prop/ABGASFountain.h"
#include "GameFramework/RotatingMovementComponent.h"
#include "ArenaBattleGAS.h"
AABGASFountain::AABGASFountain()
{
RotatingMovement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("RotatingMovement"));
ActionPeriod = 3.0f;
}
void AABGASFountain::PostInitializeComponents()
{
Super::PostInitializeComponents();
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"));
if ( !RotatingMovement->IsActive() )
{
RotatingMovement->SetActive(true);
}
else
{
RotatingMovement->Deactivate();
}
}
RotatingComponent 추가하고
타이머 설정해주면 알아서 돌아감
2. GAS로 구현
* 어빌리티 시스템 컴포넌트
- 줄여서 ASC(Ability System Component)
- 게임플레이 어빌리티 시스템을 관리하는 핵심 컴포넌트
- 게임플레이 어빌리티 및 다양한 작업을 관리하고 처리하는 중앙 처리 장치
- 액터에 단 하나만 부착 가능
- 액터는 부착된 ASC를 통해 게임플레이 어빌리티를 발동 가능
- ASC를 부착한 액터 사이에 GAS 시스템의 상호작용이 가능해짐
* 게임플레이 어빌리티
- 줄여서 GA(Gameplay Ability)
- ASC에 등록되어 발동시킬 수 있는 액션 명령
- GA의 발동 과정
- ASC에 어빌리티를 등록(ASC의 GiveAbility 함수에 발동할 GA의 타입을 전달)
- 발동할 GA 타입 정보를 게임플레이 어빌리티 스펙(GameplayAbilitySpec)이라고 함
- ASC에 어빌리티를 발동하라고 명령(ASC의 TryActivateAbility 함수에 발동할 GA의 타입을 전달)
- ASC에 등록된 타입이면 GA의 인스턴스가 생성
- 발동된 GA에는 발동한 액터와 실행 정보가 기록됨
- SpecHandle : 발동된 어빌리티에 대한 핸들
- ActorInfo : 어빌리티의 소유자와 아바타 정보
- ActivationInfo : 발동 방식에 대한 정보
- GA의 주요 함수
- CanActivateAbility : 어빌리티가 발동될 수 있는지 파악
- ActivateAbility : 어빌리티가 발동될 때 호출
- CancleAbility : 어빌리티가 취소될 때 호출
- EndAbility : 스스로 어빌리티를 마무리할 때 호출
* 타입 == GA의 클래스 정보를 Spec 구조체에 넣은 것
소유하는 액터는 AbilitySystemInterface를 구현하도록 함
GetAbilitySystemComponent랑 ASC 변수 선언
오너는 실제 작업이 일어나는 액터,
아바타는 실제 액션을 수행하진 않지만 비주얼만 수행해주는 액터
GA 만들기
// Fill out your copyright notice in the Description page of Project Settings.
#include "Prop/ABGASFountain.h"
#include "GameFramework/RotatingMovementComponent.h"
#include "ArenaBattleGAS.h"
#include "AbilitySystemComponent.h"
#include "GameplayAbilitySpec.h"
#include "GA/ABGA_Rotate.h"
AABGASFountain::AABGASFountain()
{
ASC = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC"));
RotatingMovement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("RotatingMovement"));
ActionPeriod = 3.0f;
}
UAbilitySystemComponent* AABGASFountain::GetAbilitySystemComponent() const
{
return ASC;
}
void AABGASFountain::PostInitializeComponents()
{
Super::PostInitializeComponents();
RotatingMovement->bAutoActivate = false;
RotatingMovement->Deactivate();
ASC->InitAbilityActorInfo(this, this);
FGameplayAbilitySpec RotateSkillSpec(UABGA_Rotate::StaticClass());
ASC->GiveAbility(RotateSkillSpec);
}
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* RotateGASpec = ASC->FindAbilitySpecFromClass(UABGA_Rotate::StaticClass());
if ( !RotateGASpec )
{
ABGAS_LOG(LogABGAS, Log, TEXT("No Rotate Spec Found!"));
return;
}
if ( !RotateGASpec->IsActive() )
{
ASC->TryActivateAbility(RotateGASpec->Handle);
}
else
{
ASC->CancelAbilityHandle(RotateGASpec->Handle);
}
/*if ( !RotatingMovement->IsActive() )
{
RotatingMovement->SetActive(true);
}
else
{
RotatingMovement->Deactivate();
}*/
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "GA/ABGA_Rotate.h"
#include "GameFramework/RotatingMovementComponent.h"
void UABGA_Rotate::CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility)
{
Super::CancelAbility(Handle, ActorInfo, ActivationInfo, bReplicateCancelAbility);
AActor* AvatarActor = ActorInfo->AvatarActor.Get();
if ( AvatarActor )
{
URotatingMovementComponent* RotatingComponent = Cast<URotatingMovementComponent>(AvatarActor->GetComponentByClass(URotatingMovementComponent::StaticClass()));
if ( RotatingComponent )
{
RotatingComponent->Deactivate();
}
}
}
void UABGA_Rotate::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
AActor* AvatarActor = ActorInfo->AvatarActor.Get();
if (AvatarActor)
{
URotatingMovementComponent* RotatingComponent = Cast<URotatingMovementComponent>(AvatarActor->GetComponentByClass(URotatingMovementComponent::StaticClass()));
if (RotatingComponent)
{
RotatingComponent->Activate(true);
}
}
}
GA를 부여해주는 코드
똑같이 작동함
3. 게임플레이 태그 활용
* 게임플레이 태그
- FName으로 관리되는 경량의 표식 데이터 (액터나 컴포넌트에 지정했던 태그와 다른 데이터)
- 프로젝트 설정에서 별도로 게임플레이 태그를 생성 및 관리 가능 (DefaultGameplayTags.ini에 저장됨)
- 계층 구조로 구성되어 있어 체계적인 관리 가능
ex) 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
- 게임플레이 어빌리티 시스템과 독립적으로 사용 가능
중요한 거
어빌리티에 지정한 태그 (AbilityTags 태그 컨테이너)
어빌리티 실행 시 태그 설정 (ActivationOwnedTags 태그 컨테이너)
프로젝트 세팅에서 태그 설정 가능
계층구조
ini 파일에도 잘 들어가 있음
태그 가져오기
정의해둬서 편하게 쓸 것임
어빌리티 가서 태그 설정
대표 태그 설정하고, 액티베이션 될 때 생기는 태그 설정
void AABGASFountain::TimerAction()
{
ABGAS_LOG(LogABGAS, Log, TEXT("Begin"));
FGameplayTagContainer TargetTag(ABTAG_ACTOR_ROTATE);
if ( !ASC->HasMatchingGameplayTag(ABTAG_ACTOR_ISROTATING) )
{
ASC->TryActivateAbilitiesByTag(TargetTag);
}
else
{
ASC->CancelAbilities(&TargetTag);
}
}
어빌리티 주고 뺐고는 IsRotating 태그 가지는지로 체크
대표 태그로 어빌리티 액티베이트 확인 가능
클래스 정보 담을 어레이 만들고
* 어차피 GA들은 다 저거 상속받아야 하니까 저렇게만 해두면 됨
void AABGASFountain::PostInitializeComponents()
{
Super::PostInitializeComponents();
RotatingMovement->bAutoActivate = false;
RotatingMovement->Deactivate();
ASC->InitAbilityActorInfo(this, this);
for (const auto& StartAbility : StartAbilities)
{
FGameplayAbilitySpec StartSpec(StartAbility);
ASC->GiveAbility(StartSpec);
}
}
초기화할 때 스펙 만들어서 넣어주면 됨
이러면 의존성을 떨어뜨릴 수 있음
저기 StartAbilities 넣어주는 건 에디터에서 해주면 됨
블루프린트 만들어주고
거기서 설정
이제 실행하면 정상작동 확인 가능