8. Gameplay Ability Task

골두·2024년 7월 27일

Unreal GAS Framework

목록 보기
8/8
post-thumbnail

해당 글은 https://github.com/tranek/GASDocumentation 의 설명을 한글로 번역 후 첨언 및 요약 해 나 보려고 내 입맛대로 작성한 글이다.

// TODO: GE - 2는 선행 지식이 너무 많이 필요해 추후 재작성할 예정

Gameplay Ability Tasks

Gameplay Abilities (GA)는 한 프레임에서만 실행된다는 특징을 가지고 있다. 이 특성 자체로는 많은 유연성을 제공하지는 않는다. 시간이 지남에 따라 발생하는(delay 스킬) 능력이거나, 특정 조건에 의해 발생하는 Delegate를 통해서 실행되는 능력을 수행하기 위해서는 AbilityTask 라고 불리는 숨겨진 작업을 사용한다.

GAS에서는 이 GA Task에 대해서 많은 것들을 제공해준다.

  • RootMotionSource를 사용한 캐릭터 이동 기능
  • Animation Montage 실행
  • 속성 변경에 대한 응답 기능
  • GE 변경에 대한 응답 기능
  • Player의 입력에 대한 응답 기능
  • 기타 등등...

UAbilityTask 생성자는 게임 전체에서 동시에 실행되는 GA Task의 최대 수를 1000개로 강제 하는데, RTS(실시간 전략 게임)과 같이 수백, 수천 개의 캐릭터가 동시에 존재할 수 있는 게임의 경우는 게임 설계 시 이 부분을 꼭 염두에 두고 개발하는 것이 좋다.

Custom GA Tasks

종종 사용자는 Custom GA Task를 만드는 경우가 존재한다. (C++ 경우), 샘플 프로젝트에서는 2가지 방식의 Custom GA Task 예시를 제공하는데 PlayMontageAndWaitWaitGameplayEvent 2개를 결합한 PlayMontageAndWaitForEventOwnerActor가 피해를 입을 때를 감지하고 그 상황에 맞춰 실행되는 WaitReceive 이벤트를 제공해준다.

GA Task의 구성 요소

  • 새로운 GATask instance를 생성하는 static 함수
  • GATask가 자신의 예약된 것들을 완료했을 때 실행되는 Delegates
  • GATask의 실행 시작 및 외부 Delegates 연결 등을 위한 Activate() 함수
  • 연결된 외부 Delegate 등을 전부 정리하는 OnDestroy() 함수
  • 연결된 외부 Delegate에 대한 Callback 함수
  • 멤버 변수 및 모든 내부 Helper 기능

주의점: GATask는 단 한 종류의 Delegate만 선언이 가능한데, 매개변수의 사용 여부에 관계없이 모든 출력 Delegates는 반드시 선언한 타입을 유지해야하고, 사용하지 않는 Delegate에 대해서는 기본 값을 전달해주는 특성을 가지고 있다.

GATask는 반드시 클라이언트 혹은 서버 중 GA를 소유한 한 곳에서만 실행되지만, bSimulatedTask = true라는 설정을 추가한다면 시뮬레이션 된 클라이언트에서 실행되도록 설정하는 것이 가능하다. GATask 생성자에서 InitSimulatedTask(UGameplayTasksComponent& InGameplayTasksComponent)를 재정의해서 사용하면서, Replicated할 멤버 변수를 설정한다. 이것은 특정 상황에서만 효과적인데, 예를 들어 이동에 대한 기능을 만들 때 모든 이동에 대한 변화를 Replicated하지 않고 전체 이동 GA를 시뮬레이션 하는 경우 같이 희귀한 상황에서만 유용하게 쓸 수 있다. RootMotionSource 기반 GATask에서는 이 것을 수행하는데 예제 코드의 AbilityTask_MoveToLocation.h/.cpp를 참고하면 도움이 될 것이다.

GA Task의 활용

GATask는 C++, Blueprint 둘 다 제작이 가능하다.

// 예제 코드
UGDAT_PlayMontageAndWaitForEvent* Task = UGDAT_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent(this, NAME_None, MontageToPlay, FGameplayTagContainer(), 1.0f, NAME_None, false, 1.0f);
Task->OnBlendOut.AddDynamic(this, &UGDGA_FireGun::OnCompleted);
Task->OnCompleted.AddDynamic(this, &UGDGA_FireGun::OnCompleted);
Task->OnInterrupted.AddDynamic(this, &UGDGA_FireGun::OnCancelled);
Task->OnCancelled.AddDynamic(this, &UGDGA_FireGun::OnCancelled);
Task->EventReceived.AddDynamic(this, &UGDGA_FireGun::EventReceived);
Task->ReadyForActivation();

Blueprint의 경우는 우리가 실행 시점에 직접 ReadyForActivation을 실행시켜줄 필요는 없다. Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp를 통해서 자동으로 호출되기 때문에 필요한 설정만 추가하면되고, C++에서만 ReadyForActivation, BeginSpawningActor, FinishSpawningActor 함수를 직접 호출해줘야 한다.

BP or C++에서 GATask를 수동으로 취소하려면 GATask 객체에서 EndTask()라는 함수를 호출함으로써 비동기로 진행되는 GATask를 중단시킬 수 있다.

RMS(Root Motion Source) GA Task

GAS에서는 RMS를 사용해 CharacterMovementComponent에 연결해 넉백, 복합 점프, 그랩, 돌진 등의 기능을 위해 캐릭터를 이동 시키는 GATask를 제공한다.

주의: 4버전에서는 RMS에 버그가 있는데 4.20 ~ 4.24에서는 Predict 기능에 버그가 있지만 GATask는 멀티 플레이어 버전에서는 약간의 네트워크 수정을 하면 괜찮아지고, 싱글 플레이어 버전에서는 완벽하게 동작한다.

profile
나 볼려고 만든 블로그 (블로그 이전: https://goldfrosch.tistory.com/)

0개의 댓글