Загружаем каталог…
Загружаем каталог…
[Cogito 개발기 #04] Gameplay Tag로 행동 상태와 실행 조건 관리하기 공격 중에 점프 입력이 들어오면 어떻게 처리해야 할까? 방어를 끝낸 직후 다시 방어를 시작할 수 있어야 할까? 공격 중 추가 입력이 들어오면 새 공격을 실행해야 할까, 다음 콤보를 예약해야 할까? 이런 판단에는 현재 캐릭터 상태를 여러 기능에서 공통으로 조회할 수 있는 기준이 필요하다. Cogito에서는 Gameplay Tag를 행동 식별, 상태 조회, 이벤트 전달에 사용한다. 1. 같은 태그라도 용도가 다르다 프로젝트의 태그는 DefaultGameplayTags.ini 에 등록되어 있다. 대표적인 이름을 용도별로 묶으면 다음과 같다. 구분 예시 역할 Ability Ability.Attack.Light 실행할 행동 식별 State State.Attacking 현재 상태 조회 Event Event.Attack.ComboInput 발생한 입력이나 사건 전달 Data Data.Damage 효과에 전달할 수치의 키 GameplayCue GameplayCue.Combat.Impact 연출 식별 이 접두사는 프로젝트의 명명 규칙이다. 태그 이름을 State.* 로 만들었다고 자동으로 캐릭터 상태가 추가되는 것은 아니다. Event.* 를 등록했다고 이벤트가 자동으로 발생하는 것도 아니다. 등록된 태그를 실제로 부여하고, 조회하고, 전달하는 코드나 에셋 설정이 필요하다. 2. 행동 식별과 상태 조회를 구분한다 일반 공격을 요청할 때는 Ability.Attack.Light 를 사용한다. AbilitySystemComponent->TryActivateAbilitiesByTag( FGameplayTagContainer( FGameplayTag::RequestGameplayTag( TEXT("Ability.Attack.Light") ) ) ); 반면 현재 공격 중인지 확인할 때는 State.Attacking 을 사용한다. const bool bIsAttacking = AbilitySystemComponent->HasMatchingGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Attacking") ) ); 두 태그는 질문이 다르다. Ability.Attack.Light : 어떤 행동을 실행할 것인가? State.Attacking : 지금 어떤 상태인가? 실행할 Ability의 식별 태그와 캐릭터가 보유하는 상태 태그를 구분하면 입력과 상태 판단을 읽기 쉬워진다. 3. 태그를 조회하는 쪽에서 동작을 결정한다 플레이어의 InputSpaceStart 는 공격 중이거나 피격 중이면 입력 처리를 중단한다. if ( AbilitySystemComponent->HasMatchingGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Attacking") ) ) || AbilitySystemComponent->HasMatchingGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.HitReact") ) ) ) { return; } 여기서 태그 자체가 점프를 막는 것은 아니다. 입력을 받는 함수가 태그를 조회하고 return 하기 때문에 해당 경로가 중단된다. 이 차이는 디버깅할 때 중요하다. 상태 태그가 있는데도 행동이 실행된다면 그 행동의 입력 경로 또는 Ability 활성화 조건이 해당 태그를 실제로 검사하는지 확인해야 한다. 현재 이동 입력은 조금 더 세부적으로 처리된다. State.Attacking 이 있으면 현재 Montage Section을 확인하고, End 또는 Attack 으로 시작하는 섹션에서 이동 입력을 제한한다. 즉, 공격 상태라는 큰 조건에 애니메이션의 진행 구간을 추가로 결합한 형태다. 4. 이벤트 태그는 진행 중인 행동에 정보를 전달한다 공격 중 다시 공격 입력이 들어오면 다음 이벤트를 전달한다. FGameplayEventData Payload; AbilitySystemComponent->HandleGameplayEvent( FGameplayTag::RequestGameplayTag( TEXT("Event.Attack.ComboInput") ), &Payload ); 공격 Ability는 WaitGameplayEvent 로 이 이벤트를 기다린다. UAbilityTask_WaitGameplayEvent* WaitEventTask = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent( this, FGameplayTag::RequestGameplayTag( TEXT("Event.Attack.ComboInput") ) ); if (WaitEventTask) { WaitEventTask->EventReceived.AddDynamic( this, &UCogitoGA_AttackBase::OnComboInputReceived ); WaitEventTask->ReadyForActivation(); } 이 이벤트는 다음 콤보 입력이 발생했다는 알림이다. 이벤트를 보내는 것과 ASC에 상태 태그를 추가하는 것은 별개의 동작이다. Event.Attack.ComboInput 을 보냈다고 같은 이름의 태그가 캐릭터에 지속적으로 남는 것은 아니다. 5. 짧은 상태 구간을 태그로 표현하기 방어 Ability에서는 패링 판정 구간에 State.Block.Perfect 를 직접 추가한다. ASC->AddLooseGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Block.Perfect") ) ); 이후 ParryWindow 만큼 기다리는 Ability Task를 설정한다. UAbilityTask_WaitDelay* PerfectDelay = UAbilityTask_WaitDelay::WaitDelay( this, ParryWindow ); PerfectDelay->OnFinish.AddDynamic( this, &UCogitoGA_Block::OnPerfectBlockEnded ); PerfectDelay->ReadyForActivation(); 시간이 지나면 태그를 제거한다. ASC->RemoveLooseGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Block.Perfect") ) ); 흐름을 표현하면 다음과 같다. 방어 Ability 활성화 ↓ State.Block.Perfect 추가 ↓ ParryWindow 동안 유지 ↓ State.Block.Perfect 제거 ParryWindow 는 헤더에서 기본값이 0.3f 로 선언되어 있지만 에디터에서 수정할 수 있다. 따라서 C++ 기본값과 실제 Blueprint 인스턴스의 설정값은 구분해야 한다. 6. 태그의 추가와 정리는 함께 설계한다 패링 태그는 지연 Task가 끝날 때 제거된다. 하지만 Ability가 그 전에 종료되는 경로도 고려해야 한다. 현재 방어 Ability의 EndAbility 에서는 다음 태그를 다시 정리한다. ASC->RemoveLooseGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Blocking.Stationary") ) ); ASC->RemoveLooseGameplayTag( FGameplayTag::RequestGameplayTag( TEXT("State.Block.Perfect") ) ); 따라서 정상적인 시간 만료뿐 아니라 Ability 종료 경로에서도 정리 코드를 거친다. 직접 추가한 Loose Tag를 사용할 때는 어떤 함수에서 제거하는지 함께 추적해야 한다. 같은 태그를 여러 경로에서 추가한다면 횟수와 소유 관계도 확인해야 한다. GAS의 Activation Owned Tags 처럼 Ability 실행 기간과 연동되는 설정도 있다. 이것과 C++에서 직접 추가하는 Loose Tag는 관리 경로가 다르다. 공식 문서 7. 태그의 계층은 문자열 모양 그대로 이해해야 한다 Gameplay Tag는 점으로 구분한 계층을 가진다. 예를 들어 다음 태그는 부모와 자식 관계다. State.Blocking └─ State.Blocking.Stationary 일반적인 부모 포함 매칭에서는 자식 태그를 가진 객체가 부모 태그 조회에도 매칭될 수 있다. 공식 API 문서 하지만 다음 두 태그는 이름이 비슷해도 같은 부모 아래에 있지 않다. State.Block.Perfect State.Blocking State.Block.Perfect 의 부모는 State.Block 이다. State.Blocking 의 자식이 아니다. 현재 명명 규칙에서는 패링 상태와 방어 상태를 조회할 때 이 차이를 염두에 둬야 한다. 8. 입력 제한과 Ability 제한은 구분한다 현재 플레이어 코드는 State.Block.Cooldown 이 있으면 방어 입력을 무시한다. 이것은 방어 입력 함수에서 확인되는 제한이다. 다른 코드가 방어 Ability를 직접 실행하는 경우까지 제한하려면 Ability 자체의 조건도 확인해야 한다. GAS에는 다음과 같은 설정이 있다. 설정 의미 Activation Required Tags 실행에 필요한 소유자 태그 Activation Blocked Tags 소유자에게 있으면 실행을 막는 태그 Block Abilities With Tag 실행 중 다른 Ability의 활성화를 제한하는 기준 Cancel Abilities With Tag 다른 실행 중 Ability를 취소하는 기준 태그를 활용한 행동 제어를 이해하려면 세 위치를 함께 봐야 한다. 태그를 등록하는 위치 태그를 추가하고 제거하는 위치 태그를 조회해 행동을 결정하는 위치 다음 글에서는 Event.Attack.ComboInput 이 실제 콤보 진행으로 이어지는 과정을 정리한다. 관련 코드 DefaultGameplayTags.ini MyCharacterPlayer.cpp CogitoGA_Block.cpp
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
[Cogito 개발기 #04] Gameplay Tag로 행동 상태와 실행 조건 관리하기. [Cogito 개발기 #04] Gameplay Tag로 행동 상태와 실행 조건 관리하기 공격 중에 점프 입력이 들어오면 어떻게 처리해야 할까? 방어를 끝낸 직후 다시 방어를 시작할 수 있어야 할까? 공격 중 추가 입력이 들어오면 새 공격을 실행해야 할까, 다음 콤보를 예약해야 할까? 이런 판단에는 현재 캐릭터 상태를 여러 기능에서 공통으로 조회할 수 있는 기준이 필요하다. Cogito에서는 Gameplay Tag를 행동 식별, 상태 조회, 이벤트 전달에 사용한다. 1. 같은 태그라도 용도가 다르다 프로젝트의 태그는 DefaultGameplayTags.ini 에 등록되어 있다. 대표적인 이름을 용도별로 묶으면 다음과…
Открыть источник