언어:
페이지 정보
엔진 버전:
언리얼 엔진

게임플레이 어빌리티

언리얼 엔진

GameplayAbilityTopicImage_01.png

Gameplay Ability (게임플레이 어빌리티)는 UGameplayAbility 클래스에서 파생된 것으로, 게임 내 어빌리티가 하는 일, (있다면) 시전하는 데 드는 비용, 언제 어떤 상황에서 사용할 수 있는지 등을 정의합니다. 게임플레이 어빌리티는 비동기 실행되는 오브젝트 인스턴스로 존재할 수 있기에 캐릭터 애니메이션, 파티클과 사운드 이펙트, 플레이어 입력이나 실행 도중 벌어지는 캐릭터 상호작용에 따른 분기처럼 전문화된 다단계 작업을 실행할 수 있습니다. 네트워크를 통한 자체 리플리케이트나, (클라이언트 측 예측 지원을 포함해서) 클라이언트 또는 서버 머신에서의 실행이나, 심지어 변수 동기화 및 원격 프로시저 콜(RPC) 호출도 가능합니다. 또한 게임 세션 도중 엔진에서 게임플레이 어빌리티를 구현하는 방식도 유연합니다. 예로 쿨다운(재사용 대기시간) 및 시전 비용, 플레이어 입력, 애님 몽타주가 있는 애니메이션, 어빌리티 자체를 액터에 부여할 때의 반응도 구현할 수 있습니다.

기본 사용법

게임플레이 어빌리티가 액터의 Ability System (어빌리티 시스템) 컴포넌트에 부여된 이후의 기본 실행 주기는 다음과 같습니다.

  1. TryActivateAbility (어빌리티 시전 시도) 함수는 CanActivateAbility (어빌리티 시전 가능) 함수를 호출하여 어빌리티를 즉시 시전할 수 있는지 확인하고, 가능하면 시전합니다. CanActivateAbility 는 그 자체로 실행할 수도 있는데, 예를 들면 게임에서 그 어빌리티를 나타내는 아이콘을 숨기거나 비활성화하려면 어빌리티를 실제 시전 시도하지 않고도 가능 여부를 알아야 하기 때문입니다.

  2. CallActivateAbility (어빌리티 시전 호출)은 그 어빌리티가 수행할 게임 코드를 실행하며, TryActivateAbility 에 의해 호출됩니다. CanActivateAbility 검사가 필요치 않은 경우 직접 호출할 수도 있습니다.

    • 사용자가 어빌리티의 커스텀 함수 기능으로 오버라이드해야 하는 코드는 C++ 함수 ActivateAbility 또는 블루프린트 이벤트 Activate Ability 입니다.

    • 게임플레이 어빌리티는 액터나 컴포넌트와는 달리 주 작업을 "틱" 함수에서 하지 않습니다. 대신 시전 도중 대부분의 작업을 비동기 처리하는 Ability Task (어빌리티 태스크)를 실행합니다. 그런 다음 그 태스크의 출력을 (C++ 에서) Delegate (델리게이트)에 후킹하거나 (블루프린트에서) 출력 실행 핀에 노드를 연결하여 처리합니다.

    • CommitAbility (어빌리티 확인)은 Activate 내에서 호출한 경우 어빌리티 시전 비용을 적용, 즉 Gameplay Attribute (게임플레이 어트리뷰트)에서 ("마나"든 "에너지"든 게임 시스템에 맞는) 자원을 빼고 쿨다운을 적용합니다.

    • CancelAbility (어빌리티 취소)는 어빌리티 취소 메커니즘을 제공합니다. 어빌리티의 CanBeCanceled (취소 가능) 함수가 요청을 거부할 수 있습니다. CommitAbility 와 달리, 이 함수는 어빌리티 자체 외부 호출자에서 사용할 수 있습니다. 취소가 성공하면 On Gameplay Ability Cancelled (게임플레이 어빌리티 취소 시)로 방송한 뒤 그 어빌리티를 마치기 위한 표준 코드 패스로 들어가, 어빌리티에 특수한 클린업 코드를 실핼할 기회를 주거나, 정상적으로 마쳤을 때와 다른 작동을 하도록 할 수 있습니다.

  3. 어빌리티의 정상 종료를 위해서는 EndAbility C++ 함수 호출 또는 End Ability 노드를 사용해야 합니다. 어빌리티를 취소한 경우, 이 함수는 UGameplayAbility 코드가 취소 프로세스 도중 자동 호출합니다. 어빌리티를 정상 종료하지 못하면 게임플레이 어빌리티 시스템은 어빌리티가 아직 실행 중이라 믿고 그 어빌리티 또는 그 어빌리티에 막힌 다른 어빌리티를 사용하지 못하게 될 수 있습니다. 예를 들어 게임에서 "Drink Health Potion" (생명력 포션 사용)이라는 게임플레이 어빌리티가 정상 종료되지 못한 경우, 게임플레이 어빌리티 시스템은 이 어빌리티가 끝나지 않았다 생각하므로 영원히 다른 포션을 사용한다든가, 달린다든가, 사다리를 오른다든가 하는 다른 동작을 취할 수 없을 것입니다.

UE4 프로젝트에서 이 설정 방식을 활용하려면, 액션 RPG 의 게임플레이 어빌리티NEW! 문서를 참고하세요.

태그

Gameplay Tag (게임플레이 태그)는 여러 게임플레이 어빌리티의 상호작용 방식을 결정하는 데 도움이 됩니다. 각 어빌리티의 작동방식에 따라 일정한 태그 세트를 통해 식별하고 분류해 두면 Gameplay Tag Container (게임플레이 태그 컨테이너) 및 Gameplay Tag Query (게임플레이 태그 쿼리)를 통해 다른 어빌리티의 상호작용을 지원할 수 있습니다.

게임플레이 태그 변수

목적

Cancel Abilities With Tag

태그로 어빌리티 취소 - 이 어빌리티 실행 도중 이미 실행 중인 어빌리티의 태그가 제공된 목록에 일치하면 취소합니다.

Block Abilities With Tag

태그로 어빌리티 차단 - 이 어빌리티 실행 도중 다른 어빌리티의 태그가 일치하면 실행을 차단합니다.

Activation Owned Tags

시전 오너 태그 - 이 어빌리티 실행 도중, 그 어빌리티의 오너에 이 태그 세트를 붙입니다.

Activation Required Tags

시전 필수 태그 - 이 어빌리티는 시전하는 액터 또는 컴포넌트에 이 태그가 전부 있을 때만 시전할 수 있습니다.

Activation Blocked Tags

시전 차단 태그 - 이 어빌리티는 시전하는 액터 또는 컴포넌트에 이 태그가 하나도 없을 때만 시전할 수 있습니다.

Target Required Tags

대상 필수 태그 - 이 어빌리티는 대상 액터 또는 컴포넌트에 이 태그가 전부 있을 때만 시전할 수 있습니다.

Target Blocked Tags

대상 차단 태그 - 이 어빌리티는 대상 액터 또는 컴포넌트에 이 태그가 하나도 없을 때만 시전할 수 있습니다.

리플리케이션

게임플레이 어빌리티는 내부 상태와 게임플레이 이벤트NEW! 리플리케이션을 지원하며, 리플리케이션을 끄면 네트워크 대역폭과 CPU 사이클을 절약할 수도 있습니다. 어빌리티의 Gameplay Ability Replication Policy (게임플레이 어빌리티 리플리케이션 정책)을 "예" 또는 "아니오" 로 설정하여, 어빌리티가 네트워크를 통해 자체 인스턴스를 리플리케이트할지, 상태를 업데이트할지, 게임플레이 이벤트를 전송할지 제어할 수 있습니다. 리플리케이트하는 어빌리티가 있는 멀티플레이어 게임의 경우, 리플리케이션 처리를 위한 옵션이 몇 가지 있는데, Gameplay Net Execution Policy (게임플레이 넷 실행 정책)이라 합니다.

  1. Local Predicted: 로컬 예측 - 이 옵션은 반응 속도와 정확성 사이 균형이 좋습니다. 클라이언트가 명령을 내리면 로컬 클라이언트에서 어빌리티를 즉시 실행하지만, 어빌리티의 실제 영향이 어땠는지 최종 결정은 서버에서 내립니다. 실제로 클라이언트는 서버에 어빌리티 실행 권한을 요청하지만, 클라이언트 관점의 결과를 서버가 동의할 것으로 예상하고 로컬에서 진행합니다. 클라이언트는 로컬에서 어빌리티 작동방식을 예측하므로, 클라이언트의 예측이 서버와 모순되지 않는다면 랙 없이 완전 부드럽게 느껴질 것입니다.

  2. Local Only: 로컬만 - 단순히 클라이언트가 로컬에서 어빌리티를 실행합니다. 서버에 리플리케이트하지 않습니다. 클라이언트와 서버가 같거나 (즉 물리적으로 같은 서버 머신에서 플레이하거나) 싱글 플레이어 게임이라면 서버에서도 실행되긴 합니다. 서버 머신에서 플레이하는 클라이언트가 없는 데디케이티드 서버 게임에는 적용되지 않습니다. 이 어빌리티로 클라이언트가 영향을 주는 모든 것은 일반 리플리케이션 규칙의 대상이 되며, 서버에서 보정을 받을 수도 있습니다.

  3. Server Initiated: 서버 시작 - 어빌리티를 서버에서 시작하여 클라이언트에 전파합니다. 종종 클라이언트 관점에서 서버의 실제 상황과 더욱 정확히 맞지만, 어빌리티를 사용하는 클라이언트에서는 로컬 예측이 없어 지연이 관측됩니다. 지연이 매우 짧긴 하겠지만, 어떤 어빌리티는 압박이 심한 상황에서 신속히 시전해야 하는 동작의 경우라면 특히 로컬 예측 모드만큼 부드러운 느낌이 들지 않을 것입니다.

  4. Server Only: 서버만 - 서버에서만 실행하고 클라이언트에는 리플리케이트하지 않습니다. 이 어빌리티에 영향받는 변수는 평소처럼 리플리케이트됩니다. 이 어빌리티 자체는 서버에서만 실행되기는 해도, 서버에 전권이 있는 데이터에 영향을 줄 수 있고 클라이언트에 전달된다는 뜻입니다.

인스턴스 정책

게임플레이 어빌리티를 실행하면, 보통 (그 어빌리티 유형의) 새 오브젝트를 스폰하여 어빌리티 진행 상황을 추적합니다. 배틀 로얄, MOBA, MMO, RTS 게임에서 플레이어나 AI 캐릭터 수가 백 단위를 넘는 경우 어빌리티 실행 빈도가 매우 높아지면 어빌리티 오브젝트 생성도 너무 빨라 퍼포먼스에 부정적 영향을 미칠 수 있습니다. 이를 해결하기 위해 어빌리티에 원하는 효율과 기능에 따라 인스턴스 정책을 셋 중에서 선택할 수 있습니다. 지원하는 세 가지 인스턴스 유형은 다음과 같습니다.

  • Instanced per Execution: 실행별 인스턴스 - 어빌리티를 실행할 때마다 어빌리티의 오브젝트 사본을 스폰합니다. 장점은 블루프린트 그래프와 멤버 변수를 자유롭게 사용할 수 있고, 실행 시작 시 모든 것이 기본값으로 초기화됩니다. 구현하기 가장 간단한 인스턴스 정책이지만, 드물게 실행되는 어빌리티에만 사용해야 합니다. 예를 들어 MOBA 의 "궁극기"같은 것에 좋습니다. 실행 쿨다운이 (보통 60-90 초로) 긴 경향이 있고, 이 어빌리티를 사용할 수 있는 캐릭터가 (보통 10 명 정도로) 얼마 안되기 때문입니다. 컴퓨터 제어 "미니언"의 기본 공격 어빌리티에는 좋지 않습니다. 한 번에 수백 개는 되는 데다 기본 공격은 꽤 자주 일어나므로 새 오브젝트의 생성( 및 리플리케이션)이 잦을 것입니다.

  • Instanced per Actor: 액터별 인스턴스 - 이 어빌리티를 처음 실행하면 각 액터마다 어빌리티 인스턴스를 하나 스폰한 뒤 앞으로 실행할 때 재사용합니다. 그래서 어빌리티를 실행할 때마다 멤버 변수를 지워야 하지만, 여러 번 실행에 저장하는 정보량을 절약할 수 있습니다. 어빌리티에 리플리케이트된 오브젝트를 통해 변수 변화와 RPC 를 처리할 수 있지만 실행할 때마다 새 오브젝트를 스폰하느라 네트워크 대역폭과 CPU 시간이 소모되지 않기 때문에 리플리케이션에 이상적입니다. 규모가 큰 상황에서 잘 통하는 정책으로, (예를 들어 대규모 전투처럼) 많은 액터가 어빌리티를 사용해도 처음 사용할 때만 오브젝트를 스폰하기 때문입니다.

  • Non-Instanced: 인스턴스 없음 - 가장 효율적인 인스턴스 정책입니다. 어빌리티를 실행해도 오브젝트를 스폰하는 대신 클래스 디폴트 오브젝트 를 사용합니다. 하지만 그 효율이 여러 제약을 낳습니다. 우선, 이 정책은 C++ 로만 작성한 어빌리티 전용입니다. 블루프린트 그래프는 오브젝트 인스턴스 없이 생성할 수 없기 때문입니다. 인스턴스가 없는 어빌리티의 블루프린트 클래스를 생성할 수는 있지만, 노출된 프로퍼티의 기본값을 변경할 때만 사용할 수 있습니다. 추가로, 어빌리티 실행 도중 네이티브 C++ 코드에서조차 멤버 변수를 변경할 수 없습니다. 델리게이트 바인딩도 안되고, 어빌리티의 변수 리플리케이션이나 RPC 처리도 안됩니다. 내부적인 변수 저장 (즉 어빌리티 사용자에 어트리뷰트 설정은 가능) 또는 데이터 리플리케이션이 필요 없는 어빌리티에만 사용해야 합니다. 자주 실행하고 여러 캐릭터에 사용되는 어빌리티, 예를 들어 대규모 RTS 또는 MOBA 에서 유닛의 기본 공격에 특히 잘 맞습니다.

게임플레이 이벤트로 발동

Gameplay Event (게임플레이 이벤트)는 일반 채널을 통하지 않고도 어떤 컨텍스트의 데이터 페이로드를 전송하여 게임플레이 어빌리티를 직접 발동시킬 수 있는 데이터 구조체입니다. 그 일반적인 방법은 Send Gameplay Event To Actor (액터에 게임플레이 이벤트 전송)을 호출하고 IAbilitySystemInterface 인터페이스와 그 게임플레이 이벤트에 필요한 컨텍스트 정보를 구현하는 액터를 제공하면 되지만, Ability System 컴포넌트에서 Handle Gameplay Event (게임플레이 이벤트 처리)를 바로 호출해도 됩니다. 게임플레이 어빌리티를 호출하는 정상적인 방법은 아니므로, 어빌리티 시스템에 필요할 수 있는 컨텍스트 정보는 FGameplayEventData 데이터 구조체로 전달합니다. 이 구조체는 범용이라 특정 게임플레이 이벤트 또는 어빌리티용으로 확장되지 않지만, 일반적으로 사용하기에 충분할 것입니다. 다용도 ContextHandle 칸에 필요한 부가 정보를 제공하면 됩니다.

게임플레이 이벤트가 게임플레이 어빌리티를 발동하면, Activate Ability 코드 패스를 통하는 대신 Activate Ability From Event 를 사용하므로 파라미터를 통해 부가 컨텍스트 데이터를 제공할 수 있습니다. 어빌리티가 게임플레이 이벤트에 반응하도록 하려면 반드시 이 코드 패스를 처리해야 하지만, 여기서도 유의할 점은 게임플레이 어빌리티의 블루프린트에 구현하고나면 Activate Ability From Event 가 Activate Ability 를 대신 모든 시전 트래픽을 받게 됩니다.