https://docs.unrealengine.com/5.0/ko/abilities-in-lyra-in-unreal-engine/

 

라이라의 어빌리티

라이라에서 게임플레이를 위해 게임플레이 어빌리티 시스템을 사용한 방식을 간략하게 살펴봅니다.

docs.unrealengine.com

 

라이라의 게임플레이 어빌리티 시스템

라이라에서는 GAS를 사용하여 대부분의 게임플레이를 조직한다. 어빌리티는 점프처럼 영웅 데이터에 이미 선천적으로 내재되어 있을 수도 있고, 게임 피처 같은 액션으로부터 부여받을 수도 있고, 경험이나 장비를 통해 획득할 수도 있다.

액션을 어빌리티로 구현한다. (점프, 대쉬 같은 이동 관련 액션, 사망 후 리스폰 트리거 같은 수동적인 리스닝 액션도 포함)

 

어빌리티 시스템의 코어 클래스

UAbilitySystemComponent 어빌리티 시스템 컴포넌트(Ability System Component, ASC) 는 모든 액터에 추가하여 GAS 함수 기능을 제공할 수 있습니다. 특정 액터의 스테이트를 추적하고 리플리케이션을 처리합니다.
UAttributeSet 어트리뷰트 컬렉션으로, 게임 메커니즘 내에서 특정 의미를 지닌 숫자 값입니다. 어트리뷰트는 ‘체력'과 같은 게임 리소스나, ‘기본 공격력(Base Attack Power)' 같이 다른 게임 규칙에 영향을 줄 수 있는 레퍼런스 값을 나타낼 수 있으며, 심지어 ‘적용된 대미지(Applied Damage)' 같이 비상태성 양도 나타낼 수 있습니다. 어트리뷰트 세트는 하나 이상의 어트리뷰트 프로퍼티를 정의하고 관리하고 리플리케이트합니다.
FGameplayTag 게임 오브젝트에 적용할 수 있는 임의의 계층형 식별자입니다. 게임 엔티티를 식별하고 분류하고 필터링하는 데 사용할 수 있습니다. 게임플레이 이펙트 및 어빌리티에 의해 부여되거나 철회될 수 있으며, 그 행동에 영향을 줄 수 있습니다. 오너의 아바타나 폰에 대한 대미지를 방지하는 'Gameplay.DamageImmunity' 태그를 예로 들 수 있습니다.
UGameplayAbility 요구 사항과 비용, 기타 행동을 결정하기 위한 정보와 함께 GAS가 활성화된 액터에 부여되고 해당 액터가 수행할 수 있는 게임 액션입니다. 기본 근접 공격부터 독립형 게임 메뉴 흐름, 다른 게임 액션으로 인해 트리거되는 행동 등 다양한 예가 있습니다.
UGameplayEffect 게임 액션의 결과입니다. 어트리뷰트를 일시적으로 또는 영구적으로 수정하고, 태그를 부여하거나 철회하고, 다른 어빌리티에 대한 액세스를 활성화하는 등, 다양한 이펙트를 적용할 수 있습니다. 게임플레이 이펙트는 GAS가 활성화된 액터끼리 상호작용하는 가장 일반적인 방법입니다.

 

LyraAbilitySystemComponent

AbilitySystemComponent와 관련된 클래스들

 

LyraGameState

어빌리티 시스템 컴포넌트를 가지며, 게임 페이즈를 어빌리티로 구현한다.

GameState는 클라이언트 측과 서버 측 모두에 존재하지만, 게임 모드는 서버 측에만 존재한다.

 

ULyraGamePhaseAbility 클래스를 정의한다. 어빌리티의 활성화는 해당 페이즈의 시작을, 비활성화는 페이즈 종료를 나타내게 된다.

 

이전 페이즈 어빌리티를 종료하고(실행 중인 경우) 새 페이즈 어빌리티를 활성화하는 LyraGamePhaseSubsystem을 사용하여 블루프린트에서 페이즈를 전환할 수 있다.

 

LyraAbilitySet (데이터 애셋)

라이라에서는 GameplayAbility 플러그인에서 제공하는 GameplayAbilitySet 클래스 대신에 LyraAbilitySet을 새로 정의하여 사용한다. (Primary Data Asset을 상속한다) 

 

GameplayAbilitySet 은 단순히 고정된 (키입력 - Ability) 바인딩 배열과 어빌리티 부여 함수만 존재하는데

LyraAbilitySet은 어빌리티를 Input Tag와 바인딩한다. AbilitySystemComponent에 Ability 외에도 Attribute, Effect를 부여할 수 있고 부여 후 핸들을 반환하여 나중에 따로 따로 제거할 수 있도록 설계되어 있다.

 

여기에 정의된 GiveToAbilitySystem함수는 AbilitySystemComponent에 어빌리티를 부여하는 함수이다.

Lyra AbilitySet 클래스

다양한 방법으로 Ability Set을 부여할 수 있다.

1. GameFeatureAction_AddAbilities 게임 피처 액션 활성화 시 액터에 어빌리티 세트를 부여할 수 있다.

2. LyraEquipmentDefinitions가 추가되는 액터에 어빌리티 세트를 부여할 수 있다. Experience가 로드될 때 LyraPlayerState에 의해 부여된다.

3. LyraExperienceDefinition(데이터 애셋)에서 PawnData를 참조하는데 AbilitySet은 PawnData애셋에 정의된다.

2번 경우와 마찬가지로 Experience가 로드될 때 LyraPlayerState에 의해 부여된다.

 

LyraPawnData (데이터 애셋)

Pawn (캐릭터) 하나와 관련된 여러가지 데이터 애셋을 묶어서 들고 있는 데이터 애셋이다. 

Experience가 로드될 때 ULyraPlayerState에 의해 적용된다.

 

PawnClass : 폰 클래스

AbilitySets : 부여할 어빌리티 집합 

TagRelationshipMapping : 이 폰에 의해 발생하는 액션에 대한 태그 관계 정보 배열

InputConfig : Input Action과 GameplayTag의 매핑 정보

DefaultCameraMode : 카메라 모드 정보

 

HeroData_ShooterGame 애셋 (PawnData)

 

LyraAbilityTagRelationshipMapping (데이터 애셋)

.LyraAbilityTagRelationshipMapping.h

다음은 하나의 태그에 대한 관계 정보이다. FLyraAbilityTagRelationship이라는 구조체로 정의되어 있다.

AbilityTag는 기준 태그를 뜻하고 아래 Block, Cancel, Required, Blocked는 각각 태그 집합을 뜻한다. 

 

TagRelationships_ShooterHero 애셋

에디터에서 확인한 TagRelationships_ShooterHero 애셋을 보면 여러가지 태그에 대한 관계 정보를 확인할 수 있다.

Ability.Type.Action.WeaponFire 태그를 예시로 보면 이 태그가 활성화되어 있으면 Emote와 Reload가 Block되며, 

Emote와 Reload가 활성화 된 상태에서 이 태그가 활성화되면 Emote와 Reload가 Cancel 될 수 있다는 것을 알 수 있다.

 

LyraGlobalAbilitySystem

게임에 존재하는 모든 AbilitySystemComponent를 추적하고 상호작용할 수 있도록 해주는 서브시스템이다.

어빌리티 시스템 컴포넌트는 초기화 중에 자동으로 서브시스템에 등록된다.

이 서브시스템은 모든 등록된 어빌리티 시스템 컴포넌트에서 어빌리티와 게임플레이 이펙트를 제거하거나 부여하는 블루프린트 호출 가능 함수를 제공한다.

 

LyraGameplayAbility

라이라에서는 AbilitySet의 경우와 비슷하게 Ability 클래스도 새로 만든다. 하지만 이전과 달리 기존의 Gameplay Ability를 상속받아 구현한다.

Ability 클래스의 계층 구조

 

기본 Gameplay Ability 클래스의 기능
GameplayAbility의 중요한 함수들

 

커스텀 Ability 클래스에서 편리하게 느껴지는 함수들은 여러 종류의 Getter 함수들이다.

부모 클래스(Gameplay Ability)의 CurrentActorInfo에 접근하여 OwnerPlayerController, AbilitySystemComponent, AvatarActor, SkeletalComponent 등 오브젝트를 필요한 타입으로 캐스팅하여 반환한다.

예를 들어 아래와 같은 구문은 Ability로부터 사용자 캐릭터의 포인터를 반환한다.

return (CurrentActorInfo ? Cast<ALyraCharacter>(CurrentActorInfo->AvatarActor.Get()) : nullptr);

 

LyraGameplayAbility 클래스에 선언된 다양한 Getter 함수들

 

어빌리티의 활성화 그룹

LyraGameplayAbility의 활성화 그룹

활성화 그룹(Activation Group)은 어빌리티가 자유롭게 활성화될 수 있는지 아니면 해당 어빌리티가 다른 전용 어빌리티를 차단하거나 중단할지를 결정한다. TagRelationship 애셋을 적용하여 복잡한 로직을 쉽게 적용할 수 있다.

 

1. Independent

ㄴ 어빌리티가 다른 어빌리티를 차단하거나 대체하지 않는다. (예시 : 리듬 게임에서 여러개의 키를 동시에 눌러도 모든 키가 정상적으로 입력됨)

 

2. Exclusive_Replaceable

ㄴ 어빌리티가 다른 Exclusive 어빌리티를 block하지는 않지만, 다른 Exclusive 어빌리티의 활성화에 의해 Cancel 될 수 있다. 

 

3. Exclusive_Blocking

ㄴ 어빌리티가 실행되는 동안 다른 Exclusive 어빌리티는 활성화될 수 없다. (Blocking) (리더보드나 인게임 메뉴 같은 경우 한 번에 하나만 보여야 하므로 Exclusive_Blocking으로 세팅될 수 있다)

 

어빌리티의 활성화 정책

라이라 프레임워크에 의해 어빌리티 활성화를 자동으로 처리하도록 하는 정책이다.

 

1. None : 수동 활성화

2. OnSpawn : 플레이어 스테이트에 유효한 아바타가 활당되는 즉시 활성화, 폰이 빙의 해제하기 전까지 활성화 유지

3. OnInputTriggered : 관련 입력 태그가 트리거되는 즉시 어빌리티가 한 번 활성화된다. 

4. WhileInputActive : 입력 태그가 트리거되는 한 지속적으로 어빌리티를 활성화

ㄴ Retrigger Instanced Ability가 False로 설정되어 있는 경우에는 중복 활성화 메세지가 무시되어 입력이 활성화중인 상태라면 활성화-종료-활성화-종료를 반복한다. 반대로 말하면 True인 경우에는 중복으로 활성화가 일어나 원치 않는 결과가 발생할 수 있다는 뜻이다.

 

K2 접두어가 붙은 함수

K2 접두어가 붙은 함수는 블루프린트와 C++ 모두에서 사용할 수 있다.

Ability를 활성화할 수 있는지 검사하는 함수를 C++이 아닌 블루프린트에서 구현할 수도 있다.

대부분의 라이라 Ability 블루프린트들은 ActivateAbility를 오버라이드 하여 ActivateAbility 내부에서 조건을 확인하고 조건에 따라 CommitAbility-EndAbility 혹은 EndAbillity 노드를 실행하는 방식인 것 같다.

 

Ability 사용 시 필요한 비용

일반 GameplayAbility는 비용으로써 단일 비용 및 쿨다운 게임플레이 이펙트만 허용한다.

LyraGameplayAbility는 다중 비용을 제공하기 위해 LyraAbilityCost 배열을 포함한다.

AdditionalCosts 프로퍼티는 게임 플레이 이펙트로 설정하지 않고 지정할 수 있는 추가 비용을 제공하여 기본으로 제공되는 조건에 더해 복잡한 활성화 조건을 만들 수 있게 한다.

LyraAbilityCost 클래스를 C++에서 확장하고 CheckCost 및 ApplyCost 가상함수를 오버라이드하여 커스텀 비용을 생성할 수 있다.

 

LyraPlayerState에는 GameplayTagStackContainer 프로퍼티가 정의되어 있는데 이것은 각 태그마다 int 값 할당 정보를 저장하는 컨테이너 역할을 한다.

라이라는 이 프로퍼티를 사용하여 지정된 아이템(= 특정 아이템 태그를 가진)을 주어진 양(스택) 만큼 소모하는 커스텀 Cost 클래스를 구현했다. GA_Weapon_Fire_Shotgun 어빌리티 같은 경우에는 Lyra.ShooterGame.Weapon.MagazineAmmo로 설정된 아이템 태그 스택을 추가 비용으로 사용한다.

추가 비용 배열에 ULyraAbilityCost_ItemTagStack을 하나 추가한 모습

 

어빌리티 추가/제거 시 이벤트

라이라 어빌리티는 블루프린트에서만 구현할 수 있는 이벤트를 제공한다. 활성화에 의존되지 않기 때문에 초기화나 마무리 작업에 유용하다.

1. OnAbilityAdded : 어빌리티가 부여되는 즉시 이벤트가 호출, 아바타나 Input 컴포넌트가 아직 유효하지 않을 수 있다.

2. OnPawnAvatarSet : 폰이 완전히 초기화되고 아바타와 Input 컴포넌트가 유효한 경우 호출

3. OnAbilityRemoved : 폰이 빙의 해제되거나 파괴되는 등의 이유로 ASC에서 어빌리티가 제거되려고 할 때 호출

 

어빌리티 Type Tag

라이라의 어빌리티를 계층적으로 분류하기 위해 AbilityTags 프로퍼티에 GameplayTag들을 포함한다.

이 태그들은 다른 어빌리티의 Block, Cancel, Require 세팅 관리와 TagRelationship 시스템을 통해서도 사용된다.

 

액션 어빌리티

Ability.Type.Action.Dash

Ability.Type.Action.Jump

 

패시브 어빌리티

Ability.Type.Passive.AutoRespawn

 

예를 들어 캐릭터가 죽으면 모든 액션 어빌리티를 Cancel시키는데, 이때 패시브 어빌리티는 영향을 받지 않게 된다.

 

Native 어빌리티 서브클래스 (C++에서 구현하는 어빌리티)

일부 라이라 어빌리티는 특정 활성화 조건을 적용하거나 복잡한 수학 로직을 수행하기 위해서 어빌리티를 C++에서 구현한다.

ULyraGameplayAbility_Death 사망 게임플레이 이벤트(Death Gameplay Event)를 트리거하기 위해 자동으로 구성됩니다. 모든 다른 어빌리티를 취소하고 폰의 체력 컴포넌트(Health Component)에 신호를 보내 나머지 게임 알림 및 스테이트 변경을 차례로 트리거하는 사망 프로세스를 시작합니다. 비주얼 이펙트는 이 클래스(GA_Hero_Death)의 BP 어빌리티 익스텐션에 의해 수행됩니다.
ULyraGameplayAbility_Jump 어빌리티 오너가 유효하고 로컬에서 제어되는 폰인지 확인하면서 폰의 캐릭터 무브먼트 컴포넌트(Character Movement Component)에 Jump 및 StopJumping 입력을 트리거하는 함수 기능을 제공합니다.
ULyraGameplayAbility_Reset 활성화되면, 이 어빌리티는 즉시 소유 플레이어를 초기 스폰 스테이트의 새 폰으로 리셋하고 모든 다른 어빌리티를 취소합니다.
ULyraGameplayAbility_FromEquipment 라이라의 장비 시스템과 상호작용하고 어빌리티와 관련된 아이템을 검색하는 함수 기능을 제공합니다.
ULyraGameplayAbility_RangedWeapon 무기 발사의 네이티브 구현입니다. 관련 무기와 상호작용하여 탄약 수와 적중률 등을 결정합니다. 발사 원뿔 내에서 탄도를 계산하고 적중 타깃을 찾고 유효성을 검사하는 레이 캐스팅 함수 기능을 제공합니다.

Native 어빌리티 서브클래스를 사용한다고해서 블루프린트가 아예 포함되어있지 않다는 뜻은 아니다.

핵심 로직은 C++에 구현하되 블루프린트를 어빌리티를 확장하는 용도로 사용한다.

 

LyraGameplayAbility_Death와 GA_Hero_Death

Death 어빌리티의 생성자
ActivateAbility 내부 구현, StartDeath()

LyraGameplayAbility_Death 클래스의 ActivateAbility함수는 ASC에 접근하여 AbilityTypesToIgnore 태그를 가진 어빌리티를 제외한 모든 어빌리티를 취소시킨다. 

StartDeath 함수

이후 HealthComponent에 신호를 보내 나머지 게임 알림 및 스테이트 변경을 차례로  트리거하는 사망 프로세스를 시작한다.

 

GA_Hero_Death

GA_Hero_Death 블루프린트 어빌리티에서는 비주얼 이펙트, 카메라 모드 관련 문제를 처리한다.

 

LyraGameplayAbility_Jump.cpp와 GA_Hero_Jump

GA_Hero_Jump에서는 Start AbilityState Task를 추가적으로 사용한다.

 

블루프린트 어빌리티 서브클래스 (블루프린트에서 구현하는 어빌리티)

 

GA_AbilityWithWidget

ㄴ 추가 UI 기능을 제공하는 모든 어빌리티의 베이스 클래스이다. 위젯 스테이트를 관리하므로 상태와 쿨다운, 기타 어빌리티 정보를 표시할 수 있다.

ㄴ OnAbilityAdded 이벤트는 UIExtension 서브시스템에 위젯을 등록하고 UIExtension 핸들을 보관한다.

 

GA_Melee

ㄴ Ability.Type.Action.Melee 태그가 활성화 되어있는 동안 Event.Movement.Melee 태그를 승인한다. 이 어빌리티는 InputTag.Weapon.Ads에 의해 트리거된다.

  1. 현재 장착된 무기를 찾고 관련 애니메이션 몽타주를 재생합니다.
  2. 권한을 확인(서버 전용)한 다음, 플레이어 앞에서 캡슐 트레이스를 수행합니다.
  3. 그 트레이스가 폰에 적중하면, 아군 사격을 피하기 위한 팀 비교와 레벨 지오메트리에 의해 타깃이 가려지지 않는지 확인하는 2차 확인 등의 추가 확인이 실행됩니다.
  4. 유효 적중이 등록되면, 캐릭터가 루트 모션(RootMotion) 포스를 통해 타깃을 향해 이동합니다.
  5. 다음으로 근접 대미지 게임플레이 이펙트가 타깃에 적용되고, 근접 적중 게임플레이 큐가 그 오너에게 트리거됩니다.
  6. 마지막으로, 멀티캐스트 RPC를 통해 근접 임팩트 사운드가 모든 클라이언트에서 재생됩니다.

 

GA_Weapon_Fire

ㄴ 발사 및 재장전 어빌리티는 LyraEquipmentDefinition 클래스에 의해 부여된다.

ㄴ ULyraGameplayAbility_RangedWeapon을 상속받는다.

ㄴ InputTag.Weapon.FireAuto (input binding)과 Input.Weapon.Fire 태그 (gameplay event)에 의해 활성화되며 Ability.Weapon.NoFiring 태그에 의해 금지된다.

ㄴ Ability.Type.Action.WeaponFire 태그가 활성화 되어 있는 동안 Event.Movement.WeaponFire 태그를 승인한다.

ㄴ OnAbilityAdded 이벤트는 게임플레이 태그(Ability.PlayMontageOnActivateFail.Message) 에 대한 리스너를 설정한다. 

탄약이 없는 상태에서 무기를 발사하려고 하면 해당 메시지를 수신하여 Dry Fire 몽타주를 재생한다.

 

AbilityActivation이 호출되고 캐릭터를 로컬에서 제어하는 경우, 네이티브 타기팅 트레이스 (PerformLocalTargeting 함수)를 수행하고 다음과 같은 순서로 타기팅 데이터를 빌드합니다.

  1. 어빌리티 비용(탄약 소모)은 기본적으로 커밋됩니다.
  2. 타기팅 데이터는 네트워크에서 예측되어 서버로 전송되며, 서버에서 ULyraWeaponStateComponent 에 의해 검증되고 확인됩니다.
  3. 타기팅 데이터가 서버에 의해 확인되면, BP 이벤트 OnRangedWeaponTargetDataReady 가 호출되고, 찾아낸 모든 타깃을 전달합니다. 이를 통해 어빌리티가 대미지를 적용하고 적중 이펙트를 재생할 수 있습니다.
  4. 발사 애니메이션 몽타주를 재생합니다.
  5. 타이머를 발사 간의 유효한 지연인 발사 딜레이(Fire Delay)로 설정합니다.
  6. 발사 딜레이나 타이머가 종료되면, 어빌리티가 종료됩니다. 추가 발사 시도는 활성화 로직에 의해 처리됩니다.

무기에 적중된 모든 타깃의 유효성이 검증되면 C++에서 On Ranged Weapon Target Data Ready 이벤트가 호출됩니다. 이 이벤트는 무기 오너의 발사 게임플레이 큐를 트리거하고, 그런 다음 첫 번째 hit을 파라미터로 전달합니다. 이 큐는 타깃에 적중할 때마다 반복되어 각 타깃 위치에 임팩트 게임플레이 큐를 재생합니다. 이 어빌리티에 권한이 있다면(서버), 각 타깃 적중 시 대미지 게임플레이 이펙트를 적용합니다.

 

GA_Weapon_ReloadMagazine

재장전 로직은 관련 무기의 세 가지 게임플레이 태그 스택을 중심으로 돌아간다.

Lyra.ShooterGame.Weapon.MagazineSize : 현재 무기의 탄창 하나에 허용된 최대 탄약 수

Lyra.ShooterGame.Weapon.MagazineAmmo : 현재 탄창에 남은 탄약 수

Lyra.ShooterGame.Weapon.SpareAmmo : 현재 탄창에 없는 남은 탄약 수

 

GameplayAbility.h에 선언된 K2_CanActivateAbility 함수를 블루프린트에서 오버라이딩 한다.

Lyra에서 인벤토리 아이템은 LyraInventoryItemInstance라는 오브젝트로 관리되는데 FGameplayTagStackContainer 프로퍼티를 갖고 있기 때문에 여러가지 태그들을 stack이라 불리는 int형 자료와 매핑하여 보관한다.

 

K2_CanActivateAbility의 구현 부분, return value (bool 값)와 블루출력 매개변수 Relevant Tags를 출력 매개변수로 사용하여 결과를 전달한다.

 

InventoryItemInstance에서 각각의 태그의 스택(int) 값을 확인하여 조건에 따라 3가지 상태로 나눠진다.

1. 재장전 가능 상태, true 값 반환

2. 탄창이 가득 차서 재장전이 불가능한 상태 (Ability.ActivateFall.MagazineFull)

3. 예비 탄약이 없어서 재장전이 불가능한 상태 (Ability.ActivateFall.NoSpareAmmo)

 

어빌리티 활성화 시:

  • 관련 아이템의 MagazineAmmo 스택 수를 확인합니다. 현재 탄창에 남은 탄약이 없다면, 태그를 적용하여 무기 발사 어빌리티 활성화를 억제합니다.
  • 무기 재장전 애니메이션 몽타주를 재생한 다음, GameplayEvent.ReloadDone 이벤트를 리스닝합니다. 이 이벤트는 마네킹 몽타주의 애니메이션 노티파이(Animation Notify)를 통해 전송됩니다.
  • 이벤트가 수신되면, 권한(서버)을 확인한 다음, 단순하게 캐릭터 인벤토리에서 관련 무기의 Lyra.ShooterGame.Weapon.MagazineAmmo 및 Lyra.ShooterGame.Weapon.SpareAmmo 값을 변경하는 재장전 로직을 수행합니다. 그런 다음, 어빌리티를 종료합니다.
  • 어떤 이유로든 이벤트가 처리되지 않았다면, 몽타주가 중지되거나 중단될 때 어빌리티가 로컬에서 종료됩니다. On End Ability 이벤트가 호출되어 활성화 시 설정된(앞서 설정된 경우) 사격 억제 태그를 제거합니다.

 

GA_Grenade

OnPawnAvatarSet 이벤트에서 로컬 클라이언트의 UI Extension 서브시스템에 위젯을 등록

ActivateAbility 이벤트에서는 어빌리티 비용과 쿨다운을 확인하고 Commit한다. 실패하면 어빌리티를 종료한다. 다음과 같은 프로세스를 수행한다.

GE_Grenade_Cooldown를 쿨다운 이펙트로 사용한다.

 

  1. 어빌리티 비용과 쿨다운을 커밋합니다.
  2. 수류탄 스폰 위치와 회전을 계산합니다.
  3. 권한을 확인합니다. 권한이 서버에 있으면, 계산된 값으로 수류탄 액터를 스폰하고 소유 라이라 캐릭터를 인스티게이터로 설정합니다.
  4. 스폰된 B_Grenade 액터는 폭발을 확인하고 관련 게임플레이 이펙트를 적용합니다.
  5. B_Grenade는 적 폰과 충돌 시 자동으로 폭발합니다. 유발 캐릭터(수류탄을 던진 캐릭터)에 아군 사격을 적용하지만, 해당 팀원에게는 적용하지 않습니다.
  6. 수류탄 투척 몽타주를 재생한 다음, 관련 위젯이 쿨다운 표시를 동기화할 수 있도록 게임플레이 메시지 서브시스템을 통해 남은 쿨다운 시간을 브로드캐스팅합니다. (Ability.Grenade.Duration.Message 채널로 LyraInteraction DurationMessage 메세지를 브로드캐스팅)
  7. 몽타주 완료를 기다리지 않고 즉시 어빌리티를 종료합니다.

 

GA_ADS (Aim Down Sights)

활성화된 동안 로컬에서 예측된다. (클라이언트에서 즉시 실행된 다음 서버에서 동기화하여 따라간다.)

  1. 커스텀 카메라 모드를 적용하여 필드 오브 뷰(FOV)를 좁힙니다.
  2. 캐릭터의 걷기 속도를 캐시하고 오버라이드합니다. 어빌리티가 로컬에서 예측되므로, 소유 클라이언트와 서버에서 실행한 다음, 로컬이 아닌 클라이언트에 리플리케이트합니다.
  3. 임시 입력 매핑 컨텍스트를 적용하고 배수가 더 작은 입력에 그 이동 입력을 오버라이드합니다. 입력 규모를 줄임으로써 추가 이동 입력은 더 작은 가속을 생성하고, 가속 값이 더 작은 서버에 복제되어 캐릭터가 조준하는 동안 걷게 합니다.
  4. 로컬 플레이어의 경우, UI를 업데이트하고 ‘조준 시작' 사운드를 재생합니다. (Ability.ADS.Message 채널로 Struct_UIMessaging 구조체를 전달)
  5. 입력 버튼을 놓을 때까지 기다렸다가, 버튼을 놓으면 어빌리티를 종료합니다.

활성화 도중에 우선순위가 더 높은 Input Mapping Context를 Enhanced Input Local Player Subsystem에 포함하여 활성화 중에 플레이어의 Aim Speed를 오버라이드 하며, EndAbility에서 InputMappingContext를 제거한다.

 

GA_Hero_Dash

 

GE_HeroDash_Cooldown 게임플레이 이펙트는 액터에 GameplayCue.Character.Dash.Cooldown 태그를 적용한다.

 

  1. 어빌리티 비용을 확인합니다. 비용을 지불 가능하면 비용을 커밋하고, 아니면 어빌리티를 종료합니다.
  2. 로컬 컨트롤을 확인하고, 서버에서 어빌리티를 종료합니다.
  3. 로컬 클라이언트에서, 입력 및 시선 방향에 따라 질주 방향을 선택합니다. 이동 입력이 없다면, 이 어빌리티는 클라이언트에서 종료됩니다(질주는 질주 방향 입력이 있을 때만 발생합니다).
  4. 이동 방향과 캐릭터의 오리엔테이션에 따라 재생할 애니메이션 몽타주를 선택합니다.
  5. 캐릭터가 웅크리고 있다면 웅크린 자세에서 벗어납니다.
  6. 어빌리티에 권한이 없다면(로컬 클라이언트), 서버 RPC를 통해 질주 방향과 선택한 몽타주를 리플리케이트합니다.
  7. 소유 클라이언트와 서버 양측에서 선택된 몽타주를 재생한 다음, 질주 방향으로 루트 모션 포스를 적용합니다.
  8. 메시징 서브시스템을 통해 메시지를 전송하여 클라이언트 측 UI에서 쿨다운 시간을 동기화할 수 있게 합니다. (Ability.Dash.Duration.Message 채널로 LyraInteractionDurationMessage 메세지를 브로드캐스팅)
  9. 서버에서 질주 이펙트 게임플레이 큐를 트리거하여 모든 클라이언트에 리플리케이트되도록 합니다.
  10. 루트 모션 포스가 완료되면, 추가로 잠시 딜레이한 다음, 어빌리티를 종료합니다. 이렇게 하면 추가 지연 시간 동안 부여된 어빌리티 태그를 유지하고 사격이나 점프 같은 다른 액션이 제한합니다.

 

FLyraGameplayEffectContext

기본 GameplayEffectContext 구조체

 

GAS에서 제공하는 기본 GameplayEffectContext 구조체에서 확장되어 GameplayCueNotifies에 전송할 추가 데이터 멤버와 함수를 정의한다.

FGameplayEffectContext는 구조체 유형이므로, 언리얼과 게임플레이 어빌리티 시스템에서 제대로 인식할 수 있는 대체 유형이 필요합니다. 라이라 게임플레이 이펙트 컨텍스트는 다음과 같은 여러 함수를 오버라이드합니다.

 

Duplicate() HitResults 및 메모리 복사가 불가능한 다른 멤버에 대한 전체 복사를 수행합니다.
GetScriptStruct() FLyraGameplayEffectContext::StaticStruct() 를 반환하여 블루프린트에 올바른 리플렉션 데이터를 제공합니다.
NetSerialize() 정의된 모든 추가 멤버에 대한 리플리케이션을 추가합니다.

 

라이라 게임플레이 이펙트 컨텍스트에 대해 구조체 템플릿(TStructOpsTypeTraits<> )이 정의됩니다. 이 헬퍼 구조체는 복제 및 시리얼라이제이션 함수 기능을 모두 바인딩하여 리플리케이션 시스템에서 사용할 수 있게 만듭니다.

 

라이라 어빌리티 시스템 글로벌(Lyra Ability System Globals) (ULyraAbilitySystemGlobals) 클래스는 어빌리티 시스템 글로벌(Ability System Globals) (UAbilitySystemGlobals) 클래스를 확장하고, AllocGameplayEffectContext() 함수를 오버라이드하여 라이라 게임플레이 이펙트 컨텍스트 구조체를 구성하고 반환합니다.

이를 통해 게임플레이 어빌리티 시스템이 새 게임플레이 이펙트 컨텍스트 오브젝트가 생성될 때마다 확장된 구조체를 할당하도록 합니다.

 

추가 데이터에 액세스하는 방법

라이라 게임플레이 이펙트 컨텍스트 구조체는 구조체 유형이기 때문에 그 데이터에 액세스하기 위해 블루프린트 노출 함수를 직접 포함할 수 없습니다.

이 제한을 해결하는 방법은 접근자를 블루프린트 함수 라이브러리에서 스태틱 함수로 구현하고, 컨텍스트 핸들(Context Handle)을 입력 파라미터로 전달한 다음, 내부적으로 파생된 구조체 유형에 캐스팅하는 것입니다.

헬퍼 함수 FLyraGameplayEffectContext::ExtractEffectContext 는 특수 유형에 대한 컨텍스트 포인터 캐스팅을 처리합니다. 현재 이러한 방식을 FLyraGameplayAbilityTargetData_SingleTargetHit 구조체에서 사용하고 있습니다.

비슷한 방식을 'FGameplayCueParameters'를 통해 게임플레이 큐에 전달된 이펙트 컨텍스트 핸들을 캐스팅하는 데 사용하여 추가 함수 기능에 액세스할 수 있습니다.

 

ULyraAttributeSet, ULyraCombatSet, ULyraHealthSet

기본 AttributeSet을 상속받는 LyraAttributeSet을 사용한다.

ㄴ Get, Set, Initialize 함수 기능에 대한 값과 게임플레이 어트리뷰트 프로퍼티를 자동화하기 위한 편리한 ATTRIBUTE_ACCESSORS 매크로를 제공한다.

 

라이라에서는 다음 두 개의 특수 어트리뷰트 세트 클래스를 제공한다.

 

LyraHealthSet에는 캐릭터의 현재 체력과 최대 체력을 관리하는 어트리뷰트가 포함되어 있다.

Health 현재 체력 값으로, MaxHealth가 최대치입니다.
MaxHealth 최대 허용 체력 값을 결정합니다.
Healing 캐릭터에 적용된 치유량을 누적합니다. 체력 값에 영향을 준 다음, 자동으로 0으로 리셋됩니다.
Damage 캐릭터에 적용된 대미지 양을 누적합니다. 체력 값에 영향을 줍니다.

체력이 고갈되면 실행되는 FLyraAttributeEvent 델리게이트를 구현하는데, 게임에 체력 값을 노출하고 사망을 처리하고자 체력 알림을 수신하기 위해 이 델리게이트에 다른 클래스들이 바인딩된다.

 

LyraCombatSet에는 데미지 및 치유에 대한 지원을 제공한다. 

BaseDamage 대미지 실행 시 가해질 베이스 대미지 양입니다. 대미지 실행 계산에 입력으로 제공되어 실제 가해진 대미지를 결정합니다.
BaseHeal 치유가 실행될 때 회복되는 체력 양입니다.

 

치유 및 대미지 작동 방식

기본으로 체력 어트리뷰트는 모디파이어로부터 숨겨지므로, 정규 어트리뷰트 등의 게임플레이 이펙트에 의해 직접 변경될 수 없습니다. 대신, Healing 어트리뷰트와 커스텀 실행 ULyraHealExecution 및 ULyraDamageExecution 을 통해 간접적으로 값이 설정됩니다.

대미지와 치유를 어트리뷰트로 취급하면 수정된 어트리뷰트에서 개별 대미지 인스턴스를 분리할 수 있어 대미지 값으로 작업하는 것이 더 쉬워집니다. 이를 통해 중요 어트리뷰트를 실수로 수정하는 일을 방지할 수 있습니다. 체력 값은 게임플레이 이펙트 모디파이어로부터 숨겨지므로, 베이스 값 위에 기간 이펙트나 무한 이펙트를 적용하여 장기적인 측면에서 문제를 일으킬 위험이 없습니다.

 

치유 실행

ULyraHealExecution은 소스에서 BaseHeal 어트리뷰트의 스냅샷을 찍은 다음, 0으로 고정하여 마이너스 치유를 방지합니다. 마지막으로, 타깃(Target) 의 Health 어트리뷰트를 수정합니다. 이 작업은 소스에서 수행되므로, 체력 값이 문제없이 수정될 수 있습니다.

 

대미지 실행

ULyraDamageExecution은 BaseDamage 및 Health 어트리뷰트 값을 집계합니다. BaseDamage는 소스에서 캡처되고 스냅샷이 찍히지만, Health는 타깃에서 캡처됩니다. 그런 다음, 임팩트 위치를 확인합니다(이를 통해 대미지 수치 이펙트를 스폰할 위치를 파악합니다).

아군 사격을 위해 타깃의 팀을 확인하고, 거리와 피지컬 머티리얼에 따라 어테뉴에이션을 적용합니다. 마지막으로, 타깃의 Health 어트리뷰트를 수정합니다. 이 작업은 소스 코드에서 수행되므로, 체력 값이 문제없이 수정될 수 있습니다.

대미지 수치 게임플레이 큐는 체력 어트리뷰트 변경 사항을 그 크기로 수신하도록 설정되고 정규화되지 않은 원시 값에서 디스플레이를 파생합니다.

 

추가 정보

대미지 수치 작동 방식

대미지 어빌리티가 활성화되면, 테스트를 실행하여 무엇에 적중했는지 확인한 다음, 어빌리티가 타깃 액터에 대미지 게임플레이 이펙트를 적용합니다.

GameplayEffectParent_Damage_Basic (또는 거기서 상속된 모든 자손)은 무기 캐스트 및 수류탄에 의해 적용됩니다. 그러면, BaseDamage를 체력으로 변환하고 아군 사격을 필터링하는 실행을 통해 대미지가 적용된 다음, 게임플레이 큐 GameplayCue.Character.DamageTaken 의 크기가 LyraHealthSet.Health 큐에 적용됩니다.

GCN_Character_DamageTaken 이 클라이언트에서 호출됩니다. 이는 이펙트 인스티게이터가 로컬 플레이어인 경우에만 표시됩니다. 대미지는 게임플레이 큐의 원시 크기에 의해 결정됩니다. 위치는 적중 결과의 위치 값에 의해 결정되며, 위치 값은 로컬 컨트롤러의 ULyraNumberPopComponent에 전달됩니다. 이 컴포넌트는 디스플레이와 풀링을 처리하며, 적중 위치에 나이아가라 이미터를 스폰하고 구성하여 실제 대미지를 표시합니다.

 

블루프린트 애셋 명명 규칙

앞서 다른 튜토리얼 프로젝트에서는 일반적인 블루프린트 접두사를 BP로 사용했으나 여기에서는 B로 사용한다.

 

+ Recent posts