레거시 경로 제거 & 점프어택 임팩트 타이밍 분리
1. 코드 안전교체 - 검증 후 레거시를 지운다
6/26엔 순수 가산 + opt-in(default 꺼짐) 으로 신규 Bounds 경로를 레거시 소켓 경로 옆에 깔았음. 무회귀가 목적이었음. 데이터로 켜서 검증이 끝났으니, 이제 2단계 = 레거시 경로 삭제.
❌ Before — 두 경로 공존 (폴백 분기 + 죽은 코드)
if (HitParts.IsEmpty())
{
BuildTracePoints(CurrentPoints); // 레거시 소켓 보간
if (CurrentPoints.IsEmpty()) return;
}
// ... 파트별로 bUseBoundsTrace ? 바운드 : 소켓 폴백 분기
✅ After — Bounds 단일 경로
if (HitParts.IsEmpty())
{
return; // opt-in 안 했으면 그냥 끝
}
// 파트별 분기는 '형상'만: 검=SweptLongAxis / 방패=SingleSphere
bBuilt = (Part.BoundsTraceShape == ERetrieveBoundsTraceShape::SingleSphere)
? URetrieveWeaponTraceLibrary::BuildBoundsSphere(...)
: URetrieveWeaponTraceLibrary::BuildBoundsTrace(...);
BuildTracePoints()함수 통째로 삭제, 단일 메시SweepSegment/PreviousTracePoints/bHasValidPreviousTracePoints경로 전부 제거.- 파트 분기에서
bUseBoundsTrace(소켓이냐 바운드냐) 갈래도 제거 → 이제 Bounds가 유일 경로, 분기는 형상(검/방패)뿐. - 순효과: GA_Attack.cpp −106줄. 분기·죽은 필드·이중 상태가 한꺼번에 사라짐.
교훈: opt-in 가산은 마이그레이션의 절반일 뿐임. 검증이 끝나면 레거시를 지워야 분기·죽은 상태가 안 쌓인다. "안전하게 도입"과 "과감하게 제거"는 한 세트.
2. 점프어택 ① — AoE 중심을 소켓 → 검 바운드로 정렬
착지 AoE 중심이 Weapon_R 소켓 위치였음 → #6에서 평타가 검 바운드를 쓰는데 점프슬램만 소켓이라 시각/판정이 어긋남. 평타와 동일하게 히트볼륨 메시의 바운드 중심으로 통일.
TArray<FRetrieveEquippedWeaponMesh> HitParts;
CachedWeaponComponent->GetHitVolumeMeshes(HitParts);
if (HitParts.Num() > 0 && IsValid(HitParts[0].Mesh))
{
// 평타와 같은 지오메트리: 컴포넌트 트랜스폼으로 월드 바운드 중심
Center = HitParts[0].Mesh->CalcBounds(HitParts[0].Mesh->GetComponentTransform()).Origin;
}
else { /* 소켓 폴백 (히트볼륨 opt-in 안 한 무기) */ }
6/26 TIL이 예고한 "#3 점프슬램이 검 바운드를 그대로 가져다 씀"이 실제로 실현된 지점. 판정 지오메트리를 한 소스로 모으니 스킬 간 일관성이 공짜로 따라옴.
3. 점프어택 ② — 임팩트 타이밍을 물리 착지에서 분리 + 멱등 가드
문제: AoE가 "물리 착지(HandleLanded)" 한 곳에만 묶여 있었음
물리 착지 = 캐릭터 캡슐이 바닥에 닿는 순간. 하지만 검이 바닥을 내려찍는 시각적 임팩트 프레임과는 다름 → AoE가 늦거나 어긋나 보임.
해결: 애님 노티파이 게임플레이 이벤트를 1순위 트리거로
몽타주의 임팩트 프레임에 AnimNotifyState_AttackImpact가 GameplayEvent.Attack.Impact를 쏘고, GA가 그걸 듣는다.
ImpactEventTask = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
this, RetrieveGameplayTags::GameplayEvent_Attack_Impact, nullptr, false, true);
ImpactEventTask->EventReceived.AddDynamic(this, &ThisClass::HandleImpactEvent);
ImpactEventTask->ReadyForActivation();
void UGA_JumpAttack::HandleImpactEvent(FGameplayEventData) { ApplyLandingAoe(); }
문제: 트리거가 여러 개가 되니 AoE가 중복으로 터질 수 있음
이제 ApplyLandingAoe를 부르는 곳이 3군데 — ① 임팩트 노티파이(원하는 타이밍) ② 물리 착지 HandleLanded(폴백) ③ HandleMontageCompleted(노티파이·착지 둘 다 놓쳤을 때 최후 보루).
→ bool 멱등 가드로 "정확히 한 번" 보장. 먼저 부른 놈이 이기고 나머지는 no-op.
void UGA_JumpAttack::ApplyLandingAoe()
{
if (bLandingAoeApplied) return; // ← fire-once 가드
bLandingAoeApplied = true;
// ... AoE 적용
}
// EndAbility에서 bLandingAoeApplied = false 로 리셋
핵심: 게임플레이 효과 타이밍을 물리 이벤트가 아니라 애님 노티파이에 묶으면 시각적으로 정확해짐. 단, 여러 트리거가 한 효과로 수렴하면 멱등 가드는 선택이 아니라 필수(중복 데미지 = 버그). 가드만 있으면 호출 순서/경합은 신경 안 써도 됨.
비교 정리
| 구분 | ❌ Before | ✅ After |
|---|---|---|
| 평타 트레이스 경로 | Bounds + 소켓 폴백 공존 | Bounds 단일 (소켓 경로·BuildTracePoints 삭제) |
| 파트 분기 | 소켓/바운드 + 형상 | 형상(검/방패)만 |
| 점프 AoE 중심 | Weapon_R 소켓 위치 |
히트볼륨 메시 바운드 중심 (평타와 통일) |
| 점프 AoE 타이밍 | 물리 착지 1곳 | 애님 임팩트 이벤트 1순위 + 착지/몽타주완료 폴백 |
| 중복 방지 | (트리거 1개라 불필요) | bLandingAoeApplied 멱등 가드 (3트리거 fire-once) |
핵심 요약
- opt-in 가산은 마이그레이션의 절반. 검증이 끝나면 레거시 경로를 지워야 분기·죽은 상태가 안 쌓인다. ("안전 도입" + "과감 제거" 한 세트)
- 판정 지오메트리를 한 소스(검 바운드) 로 모으면 평타·점프슬램 등 스킬 간 일관성이 공짜로 따라온다.
- 게임플레이 효과 타이밍은 물리 이벤트보다 애님 노티파이 게임플레이 이벤트에 묶어야 시각적으로 정확하다 (물리 착지는 폴백).
- 한 효과로 수렴하는 트리거가 둘 이상이면 bool 멱등 가드로 fire-once를 강제한다 — 그러면 호출 순서·경합을 신경 쓸 필요가 없다.
'내일배움캠프_Unreal > TIL' 카테고리의 다른 글
| 내일배움캠프_Unreal/TIL - Day 148 (260702) (0) | 2026.07.02 |
|---|---|
| 내일배움캠프_Unreal/TIL - Day 147 (260701) (0) | 2026.07.01 |
| 내일배움캠프_Unreal/TIL - Day 143 (260625) (0) | 2026.06.25 |
| 내일배움캠프_Unreal/TIL - Day 141 (260623) (0) | 2026.06.23 |
| 내일배움캠프_Unreal/TIL - Day 140 (260622) (0) | 2026.06.22 |