언스턱(강제 리스폰) - 새 로직 대신 "정규 사망 흐름" 재사용
1. KillOwner - Health를 직접 0으로 세팅해 사망을 "단일 소스"로 구동
사망 파이프라인의 트리거는 결국 Health 0. 그래서 데미지 GE를 만들지 않고 어트리뷰트 베이스를 직접 0으로 세팅 → HandleHealthChanged가 나머지를 알아서 굴림.
void URetrieveHealthComponent::KillOwner()
{
if (!AbilitySystemComponent || !AttributeSet) return;
if (bDeathStarted) return; // 이미 사망 처리 중이면 재진입 방지
// GE 파이프라인 우회 — ResetHealth와 동일 기법. Health 0 → GA_Die → ... → Result.
AbilitySystemComponent->SetNumericAttributeBase(UCombatAttributeSet::GetHealthAttribute(), 0.f);
}
- 재진입 가드:
bDeathStarted로 이미 죽는 중이면 no-op. SetNumericAttributeBasevs GE: 환경적 강제 사망은 데미지 계산·감쇠·면역이 필요 없으니 베이스 직접 세팅이 더 정확. (실데미지가 아니라 "상태를 죽음으로 만든다".)
2. UI 가드 이중화 + 버튼 부재 안전 처리
"강제 리스폰" 버튼은 인게임에서만 의미가 있음. 메인 메뉴에서 설정을 열면 숨겨야 하고, 세션 상태가 바뀐 뒤 눌릴 가능성도 막아야 함.
// NativeConstruct — 인게임이 아니면 버튼 숨김. WBP에 버튼이 아직 없으면 FindWidget이 null → 안전 무시.
if (UButton* RespawnButton = FindWidget<UButton>(this, TEXT("Btn_Respawn")))
{
const bool bInGame = GS && GS->GetSessionState() == ERetrieveSessionState::InGame;
RespawnButton->SetVisibility(bInGame ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
}
// HandleRespawn — 클릭 시에도 세션 상태 재확인(가시성 가드가 뚫려도 방어)
if (!GS || GS->GetSessionState() != ERetrieveSessionState::InGame) return;
if (auto* PC = Cast<ARetrievePlayerController>(GetOwningPlayer())) PC->RequestUnstuck();
RequestClose(); // 요청 후 패널 닫아 게임 입력 복귀
- 이중 가드: 표시(Visibility) + 실행(핸들러) 양쪽에서 인게임 확인.
- 버튼 부재 내성:
FindWidgetnull 허용 → C++ 선반영 후 WBP에 버튼을 나중에 추가해도 크래시 없음(배선 순서 독립). - 곁들여
RequestQuitGame(포즈 팝업 게임 종료, 로컬QuitGame)도 추가.
3. (버그 수정) 낙하 데미지로 원소 게이지가 차던 문제
공격자 측 "적중" 이벤트(원소 게이지 충전 등 "남을 때렸다" 피드백)가, 낙사/환경 데미지(instigator == target인 self-damage)에도 발행되던 게 원인.
❌ Before — 무조건 공격자 적중 이벤트 발행
EventData.EventTag = AttackerEventTag;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(AttackerActor, AttackerEventTag, EventData);
✅ After — 자기 자신에게 입힌 데미지는 "적중" 아님 → 제외
if (TargetActor != AttackerActor) // self-damage(낙하 등) 제외
{
EventData.EventTag = AttackerEventTag;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(AttackerActor, AttackerEventTag, EventData);
}
낙사 강제 리스폰을 붙이니 드러난 버그. "적중" 피드백은 남을 때렸을 때만 - instigator와 target이 같으면 전투 적중이 아니다.
4. (튜닝) 낙법 실패 착지 몽타주 배속
착지 경직이 길게 느껴져, 낙법 실패 몽타주에 재생 배속 파라미터를 추가(값만, 로직 동일).
// 헤더: EditDefaultsOnly, ClampMin=0.1
float LandingFailMontagePlayRate = 1.f;
// 재생: 배속 전달 (>1.0 = 짧게)
PlayAnimMontage(LandingFailMontage, LandingFailMontagePlayRate);
비교 정리
| 구분 | ❌ 안 했다면 | ✅ 이번 구현 |
|---|---|---|
| 사망 트리거 | 데미지 GE 조작 | SetNumericAttributeBase(Health, 0) + 재진입 가드 |
| 리스폰 버튼 | 항상 노출/무가드 | Visibility + 핸들러 재확인 + FindWidget null 내성 |
| 낙하 데미지 | 원소 게이지 충전됨(버그) | instigator==target이면 적중 이벤트 제외 |
| 착지 경직 | 고정 길이 | LandingFailMontagePlayRate로 배속 튜닝 |
핵심 요약
- 사망 트리거는 Health를 직접 0으로(
SetNumericAttributeBase) 세팅해 파이프라인을 단일 소스로 구동,bDeathStarted로 재진입 방지.. - UI 버튼은 표시·실행 이중 가드 +
FindWidgetnull 내성으로, C++를 먼저 넣고 WBP 배선을 나중에 해도 안전하게 한다. - "적중" 피드백은 instigator ≠ target일 때만 — self-damage(낙사 등)로 원소 게이지가 차는 버그를 이 한 줄로 막는다.
'내일배움캠프_Unreal > TIL' 카테고리의 다른 글
| 내일배움캠프_Unreal/TIL - Day 152 (260708) (0) | 2026.07.08 |
|---|---|
| 내일배움캠프_Unreal/TIL - Day 151 (260707) (0) | 2026.07.08 |
| 내일배움캠프_Unreal/TIL - Day 149 (260703) (0) | 2026.07.03 |
| 내일배움캠프_Unreal/TIL - Day 148 (260702) (0) | 2026.07.02 |
| 내일배움캠프_Unreal/TIL - Day 147 (260701) (0) | 2026.07.01 |