🎮 구현 목표
전투 중 입력으로 스킬을 캔슬하거나 피격으로 몽타주가 중단되는 등, 몽타주가 끝까지 재생되지 않는 상황에서도 캐릭터 상태가 정상적으로 복구되는 전투 시스템을 구현하고자 했습니다.
🚨 문제 상황
몽타주가 중단되면 Gameplay Tag가 제거되지 않는 현상 발생
기존 구조에서는 공격/피격 시작 시 상태 태그를 추가하지만, 종료 시 태그 제거는 AnimNotify에 의존했습니다.
AnimNotify의 치명적인 한계:
- ❌ 몽타주가 중단되면 해당 프레임의 Notify가 호출되지 않음
- ❌ 블렌드 아웃 발생 시 몽타주 끝부분 Notify가 누락될 위험
즉, 몽타주가 끝까지 재생되고 블렌드 없이 종료된다는 보장이 있어야만 AnimNotify로 상태 관리가 가능합니다.
실제 발생한 문제:
- 공격 중 회피 →
TAG_Character_State_Attacking미제거 → 캐릭터 영구 이동 불가, 공격 입력 무시 - 피격으로 공격 중단 →
TAG_Character_State_Attacking미제거 → 캐릭터 영구 이동 불가, 공격 입력 무시
💭 해결 방법
"태그 추가를 호출 로직에서 했으면, 제거도 호출 로직에서 하면 되지 않을까?"
핵심은 몽타주 종료 시점에 무조건 호출되는 콜백을 찾는 것이었습니다.
이 때 알게된 것이 AnimInstance에 있는 FOnMontageEndedDelegate였습니다. 몽타주가 재생되고나면 어떤 이유에서든 몽타주가 종료될 때 호출을 보장해줍니다. 심지어 두 번째 매개변수로 중단 여부까지 확인할 수 있으니 정상적으로 재생이 끝났을 때와 중단되었을 때의 로직 처리를 구분하여 로직을 처리하기도 수월했습니다.
고려한 방법들:
- Timer 사용 → 몽타주 길이만큼 타이머 설정 후 태그 제거
- 리스크: 몽타주가 일찍 중단되어도 타이머는 계속 진행
- 판단: 근본적 해결 아님 ❌
- FOnMontageEnded Delegate 활용 ✅
- 몽타주가 어떤 이유로든 종료되면 무조건 호출
bInterrupted파라미터로 정상 종료/중단 여부 구분 가능- UE5가 제공하는 안전한 방법
🔧 구현
피격 시스템에 먼저 적용하여 검증:
void ASoulCharacterBase::HitReaction(AActor* Attacker, UDamageType* DamageType,
const FVector& HitDirection)
{
// ...
FOnMontageEnded OnMontageEnded;
OnMontageEnded.BindUObject(this, &ThisClass::RecoveryHitReaction);
AnimInstance->Montage_Play(HitReactAnimation);
AnimInstance->Montage_SetEndDelegate(OnMontageEnded, HitReactAnimation);
}
void ASoulCharacterBase::RecoveryHitReaction(UAnimMontage* AnimMontage, bool bInterrupted)
{
check(StateComponent);
RemoveState(SoulGameplayTag::Character_State_Hit);
RemoveState(SoulGameplayTag::Character_State_Down);
RemoveState(SoulGameplayTag::Character_State_Attacking);
RemoveState(SoulGameplayTag::Character_State_Attacking_Recovery);
StateComponent->ToggleMovementInput(true);
AttributeComponent->ToggleStaminaRegeneration(true, 0.5f);
}
검증 결과:
- ✅ 피격 모션 중 공격받아 중단 → 상태 정상 복구
- ✅ 피격 모션 정상 종료 → 상태 정상 복구
- ✅ 블렌드 아웃 발생 → Delegate 정상 호출
모든 태그 제거 로직을 FOnMontageEndedDelegate를 통하도록 변경했습니다.
✅ 결과
안정적인 상태 관리 시스템 구축
✅ 모든 종료 케이스 대응
- 정상 종료, 입력 캔슬, 피격 중단, 블렌드 아웃 모두 처리
✅ 상태 불일치 문제 완전 해결
- 공격 캔슬 후 이동 불가 버그 소멸
- 스태미나 재생 미복구 현상 해결
✅ 확장 가능한 구조
bInterrupted로 종료 상황별 로직 분기 가능- 새로운 몽타주 추가 시 동일 패턴 적용
AnimNotify는 특정 타이밍의 이벤트(이펙트 재생, 사운드 등)에 적합하지만, 상태 초기화처럼 반드시 실행되어야 하는 로직은 Delegate로 보장해야 합니다.
'프로젝트 회고' 카테고리의 다른 글
| [UE5 액션] 루트 모션 기반 자연스러운 대시 구현 Motion Warping (0) | 2025.12.02 |
|---|---|
| [UE5 액션] 유연한 콤보 시스템: 이벤트 기반 Perfect/Mercy 구간을 통한 공격 후딜레이 캔슬 및 콤보 연계 (0) | 2025.12.02 |
| [DirectX 11] 다중 좌표계 간 위치 동기화 (0) | 2025.12.02 |
| [UE5 액션] 상태 관리: StateComponent와 GameplayTag (0) | 2025.12.02 |
| [DirectX 11] Enum의 한계 → FSM Component (0) | 2025.12.02 |
