구현계획 — 차량부품슬롯마무리
차량 부품 슬롯 마무리 — 구현계획 (2026-04-29)
작성일: 2026-04-29 (수) 마감: 2026-05-01 (D-2) — 직후 팀플 시작 대상 레포:
D:\Unreal\VoidUnreal(코드) / 본 레포(Bootcamp-TIL)는 학습·문서 전용 기반 문서:8번과제_구현계획.md§B (차량 부품 슬롯 인터랙션) ·2026-04-29.md(어제 한 일/오늘 할 일)
0. 컨텍스트
8번 과제(언리얼 좀비 게임) Day 5. 어제(04-28) 코드/콜리전 수정은 모두 완료되었고, 오늘은 PIE 검증 + 엣지 케이스 + 차량 시동 분기 동작 확인이 본 과제. 코드 수정은 원칙적으로 없으며, 발견된 버그가 있을 때만 수정한다.
| 구분 | 04-28 완료 | 04-29 잔여 |
|---|---|---|
| E 키 통합 인터랙션 | Interact() 한 곳에서 슬롯/시동/픽업 분기 (단 한 메서드) | PIE에서 분기 우선순위 실측 |
PartType 필드 | UVOIDItemDataAsset::PartType (EVOIDVehiclePartType) 추가 | DataAsset 인스턴스 값 설정 검증 |
| 인벤토리 부품 검색 | UVOIDInventoryComponent::FindPartByType 추가 | 슬롯 → 부품 자동 매칭 동작 |
| 헬기 콜리전 충돌 | 헬기 데코 메시 콜리전 OFF + 코드에서 AStaticMeshActor 후보 컷 | 옥상에서 Sweep이 슬롯까지 도달하는지 |
| 로그 정비 | 부품 부재/타입 불일치/정상 설치/무게 변화 모두 출력 | 3종 로그 케이스 모두 재현 |
| 차량 시동 분기 | AVOIDVehicle::TryStartEngine 호출은 Interact() 안에 조건부 진입 | 슬롯 모두 채운 뒤 E 키가 시동으로 빠지는지 |
본 레포 정책: 코드 변경 지시는 작성하지 않는다. 본 문서는 PIE 검증 시나리오 · 로그 매트릭스 · 분기 우선순위 실측표가 본질.
1. 검증 시나리오 (PIE)
1.1 정상 흐름 (Happy Path)
옥상(Floor 3) 진입 후 부품 3종을 인벤토리에 넣고, 슬롯 3개 앞에서 차례대로 E.
| # | 입력 | 기대 동작 | 확인 포인트 (Output Log) | 실패 시 의심 지점 |
|---|---|---|---|---|
| 1 | Battery 부품 픽업 | InventoryComponent.AddItem 성공, 무게 +8 kg | [VOID Inventory] Add Battery → Total 8.00 / Max ... | OnWeightChanged 미바인딩 / DataAsset Weight=0 |
| 2 | Battery 슬롯 앞 E | 슬롯 분기 진입 → FindPartByType(Battery) 매칭 → TryInstallPart 성공 | [Interact] Sweep hits=N → [Slot] ... 부품 설치 완료 (Battery) → 무게 -8 | 슬롯 콜리전 채널이 Visibility Block 안 됨 / PartType enum 매핑 누락 |
| 3 | FuelTank 슬롯 앞 E | 동일 — EVOIDVehiclePartType::FuelTank 매칭 | [Slot] 부품 설치 완료 (FuelTank) 무게 -12 | DataAsset 인스턴스의 PartType이 None |
| 4 | SparkPlug 슬롯 앞 E | 3번째 설치, InstalledCount==3 도달 → bRepairComplete=true | [Vehicle] OnRepairComplete broadcast 또는 bRepairComplete=true 로그 | NotifySlotInstalled 미호출 (슬롯 → 차량 통보 누락) |
| 5 | 차량 본체 앞 E | 시동 분기 진입 → TryStartEngine(this) → true | [Interact] StartEngine Result=Success + [Vehicle] Engine started by ... | bRepairComplete=false로 남아 있거나, Sweep이 차량 본체를 못 잡음 |
단계 5 핵심:
Interact()분기 우선순위가Slot → Vehicle → Pickup순일 때, 슬롯이 모두 설치된 상태에서도 슬롯 액터가 Sweep에 잡히면 슬롯 분기로 들어갈 수 있다. 슬롯 액터 측에서bInstalled==true일 때 인터랙션을 건너뛰는 분기가 있는지 PIE에서 실측한다.
1.2 엣지 케이스
| 케이스 | 입력 상태 | 기대 동작 | 의도 |
|---|---|---|---|
| EC-1: 인벤토리 부품 없음 | Battery 슬롯 앞에서 E, 인벤토리에 Battery 미보유 | FindPartByType → nullptr → 조기 반환, Warning 로그 | 부재 케이스 가드 |
| EC-2: 슬롯-부품 타입 불일치 | Battery 슬롯 앞에서 E, 인벤토리에 FuelTank만 있음 | FindPartByType(Battery) → nullptr (FuelTank 안 잡힘) → 같은 부재 로그 | EC-1과 같은 경로 (FindPartByType이 타입 필터링하므로 Slot 측의 타입 불일치 분기는 거의 안 탐) |
| EC-2b: Slot 측 타입 불일치 분기 검증 | (강제 테스트) FindPartByType이 잘못된 부품을 반환했다 가정 | [Slot] 부품 타입 불일치 — 필요=Battery 후보=FuelTank Warning | VOIDVehiclePartSlotActor.cpp:38 로그 살아있음 |
| EC-3: 같은 슬롯 중복 설치 시도 | Battery 슬롯에 이미 설치된 상태 + 인벤토리에 Battery 또 있음 | bInstalled==true 가드로 차단 OR 다시 설치 (어느 쪽인지 PIE에서 확인) | 결정 필요 — 의도된 동작 명문화 |
| EC-4: 헬기 메시 근처 Sweep | 헬기 옆에서 E (슬롯·차량 모두 멀리) | Sweep 후보에서 AStaticMeshActor 컷, 인터랙션 미발생 | 04-28 헬기 콜리전 수정 회귀 검증 |
| EC-5: 슬롯 모두 채운 후 E (시동 분기) | 3슬롯 설치 완료, 슬롯과 차량이 가까이 배치 | Sweep이 차량 본체를 우선 잡거나, 슬롯 액터의 bInstalled 가드로 슬롯 분기 스킵 → 시동 분기 진입 | 분기 우선순위의 핵심 검증 |
| EC-6: 부품 미수집 상태 시동 시도 | 차량 본체 앞에서 E, bRepairComplete=false | TryStartEngine 진입 → false 반환, [Vehicle] Not yet repaired 로그 (또는 동등) | 시동 가드 동작 |
| EC-7: 인벤토리 가득 상태 픽업 | 무게 한도 초과 직전 부품 픽업 시도 | [VOID Interact] ... 인벤토리 가득 (.../...) | 04-28 추가된 무게 한도 로그 |
1.3 로그 검증 체크리스트
PIE 1회 실행으로 아래 모든 메시지가 로그에 찍혀야 한다 (Window > Developer Tools > Output Log).
[Interact] Sweep hits=N(E 누를 때마다, 후보 수 출력)[Interact] Hit: <Actor> (Component=...)(각 후보별)[Interact] InstallPart Slot=<Type> Part=<DataAsset> Result=Success Weight <before> → <after> / <max>(정상 설치)[Interact] InstallPart Slot=<Type> FAIL — 인벤토리에 부품 없음(EC-1)[Slot] <Name> 부품 타입 불일치 — 필요=<X> 후보=<Y>(EC-2b, 강제 시)[Slot] <Name> RemoveItem 실패(이론상 발생 불가, 가드 로그)[Slot] <Name> 부품 설치 완료 (<Type>) — Weight now <X> / <Max>(정상 3회)[Interact] StartEngine Result=Success(3슬롯 채운 뒤 차량 본체 E)[Vehicle] Engine started by BP_VOIDPlayerCharacter_C_0(시동 성공)[VOID Interact] ... 인벤토리 가득(EC-7)
2. 코드 진입점 매핑
라인 번호는 04-29 시점 D:\Unreal\VoidUnreal 직접 grep 결과 (추정 아님). PIE 도중 디버거로 진입할 때 그대로 사용.
| 클래스 / 파일 | 함수 / 멤버 | 라인 | 책임 | 의심 시 확인 항목 |
|---|---|---|---|---|
AVOIDPlayerCharacter Public/Characters/VOIDPlayerCharacter.h | void Interact(const FInputActionValue&) | h:48 | E 키 진입점 (Enhanced Input → 함수 위임) | InteractAction 바인딩 (cpp:114) 살아있는지 |
AVOIDPlayerCharacter Private/Characters/VOIDPlayerCharacter.cpp | Interact 본체 | cpp:159~ | Sweep → 후보 분류 → Slot/Vehicle/Pickup 분기 | cpp:184 Sweep hits= 로그가 0이면 콜리전 채널 / SphereTrace 반경 |
| 〃 | AStaticMeshActor 후보 컷 | cpp:204 (bStaticDecor) | 헬기 등 데코 차단 | 슬롯 액터가 AStaticMeshActor를 상속하지 않는지 (실제로는 AVOIDVehiclePartSlotActor 단독) |
| 〃 | 슬롯 분기 | cpp:223~240 | FindPartByType(SlotType) → Execute_TryInstallPart | cpp:227 CandidatePart nullptr 케이스 (EC-1) |
| 〃 | 시동 분기 | cpp:251~252 | Vehicle->TryStartEngine(this) | Sweep 후보 중 AVOIDVehicle이 잡혔는지 |
| 〃 | 인벤토리 가득 분기 | cpp:265 | 픽업 거부 메시지 | MaxCarryWeight BP Default 값 |
AVOIDVehicle Public/Vehicle/VOIDVehicle.h | NotifySlotInstalled(EVOIDVehiclePartType) | h:25 | 슬롯 → 차량 통보 (InstalledCount 증가) | h:47 InstalledCount, h:50 bRepairComplete |
| 〃 | bool TryStartEngine(AActor* Driver) | h:28 | 시동 시도, bRepairComplete 가드 | Private/Vehicle/VOIDVehicle.cpp:34 본체 |
AVOIDVehicle Private/Vehicle/VOIDVehicle.cpp | TryStartEngine | cpp:34 | GameMode 위임 자리 (TODO 미구현) | cpp:38 // TODO: AVOIDGameMode::HandleEscapeSuccess(Driver) 본 구현 — 오늘은 미구현이 정상, 로그만 |
AVOIDVehiclePartSlotActor Public/Vehicle/VOIDVehiclePartSlotActor.h | RequiredType (EVOIDVehiclePartType) | h:39 | 이 슬롯이 받을 부품 종류 | BP 인스턴스에 Battery/FuelTank/SparkPlug 각각 설정 |
| 〃 | InteractionVolume (USphereComponent) | h:30 / cpp:13~20 | Sweep 응답 콜리전 | cpp:18 ECR_Overlap, cpp:19 ECC_Visibility, ECR_Block (Sweep이 잡으려면 Visibility Block) |
| 〃 | TryInstallPart_Implementation | cpp:38~56 | 타입 검사 → RemoveItem → bInstalled=true → NotifySlotInstalled | cpp:48 RemoveItem 실패 가드 |
UVOIDInventoryComponent Public/Components/VOIDInventoryComponent.h | FindPartByType(EVOIDVehiclePartType) | h:41 | 인벤토리에서 타입 일치 첫 부품 반환 | cpp:45 본체 |
UVOIDItemDataAsset Public/Items/VOIDItemDataAsset.h | EVOIDVehiclePartType PartType | h:64 | 04-28 신설 필드 (default None) | DA_Part_Battery / FuelTank / SparkPlug 인스턴스 값 |
AVOIDGameMode Private/Core/VOIDGameMode.cpp | HandleEscapeSuccess(AActor*) | 미구현 | 시동 성공 시 레벨 전환 위임 | 오늘 미구현 → §3 TODO |
3. 차량 시동 분기 (TryStartEngine)
3.1 진입 조건
AVOIDPlayerCharacter::Interact (cpp:251)에서 Sweep 결과 중 AVOIDVehicle*로 캐스팅 성공한 후보가 있으면 진입. 슬롯 분기보다 뒤에 있으므로, 슬롯이 잡히면 시동 분기는 실행되지 않는다.
3.2 검사 로직 (AVOIDVehicle::TryStartEngine cpp:34~)
1
2
3
4
1. bRepairComplete 가드 → false면 false 반환
2. UE_LOG: "[Vehicle] Engine started by <Driver>"
3. AVOIDGameMode::HandleEscapeSuccess(Driver) 호출 ← TODO
4. true 반환
3.3 성공 시 GameMode 위임 흐름 (TODO)
1
2
3
TryStartEngine(success)
└── AVOIDGameMode::HandleEscapeSuccess(Driver) ← 미구현
└── UGameplayStatics::OpenLevel(this, "Lv_Escape")
오늘 범위 밖: GameMode 본 구현은
8번과제_구현계획.mdDay 5/6 잔여 작업 — 본 문서는 시동까지 진입 + 로그 출력만 검증한다.
3.4 분기 우선순위 실측 표 (PIE에서 채울 것)
| 상태 | E 키 입력 위치 | 실제 진입 분기 | 메모 |
|---|---|---|---|
| 슬롯 0/3 | Battery 슬롯 앞 | (예상) Slot | |
| 슬롯 1/3 | 차량 본체 앞 | (예상) Vehicle, but bRepairComplete=false → false | 로그 확인 필요 |
| 슬롯 3/3 | Battery 슬롯 앞 (이미 설치됨) | (예상) Slot or Vehicle? | EC-3, EC-5 핵심 — 실측 |
| 슬롯 3/3 | 차량 본체 앞 | (기대) Vehicle → TryStartEngine 성공 | |
| 슬롯 3/3 | 슬롯 + 차량 사이 (Sweep에 둘 다 잡힘) | (불명) | 결정 필요 |
4. 추가 작업 우선순위 (시간 남으면)
P1: HUD 차량 수리 진행도 (예상 30~45분)
UVOIDHUDWidget에RepairProgress: ProgressBar또는Text "N/3"위젯 추가AVOIDVehicle::OnSlotInstalled델리게이트에 BindUFunction →InstalledCount/3갱신- BP에서
OnRepairComplete시 텍스트 색상 변경 (“Press E to Start”) - 전제: HUDWidget이 PlayerController에서 이미 활성화되어야 함 (오늘 할 일 §GUI 항목)
P2: 레벨 전환 (예상 45~60분)
AVOIDGameMode::HandleEscapeSuccess(AActor* Driver)함수 추가 (Header + cpp)- 본문:
UGameplayStatics::OpenLevel(this, FName("Lv_Escape")) AVOIDVehicle::TryStartEnginecpp:38 TODO 자리에서Cast<AVOIDGameMode>(GM)->HandleEscapeSuccess(Driver)호출 활성화Lv_Escape빈 레벨 + 엔딩 텍스트 위젯 (또는Lv_VoidProto로 임시 자기참조)
P1·P2 모두 시간 부족 시 04-30로 이월 — 본 문서의 1차 목표는 §1.1~§1.3 검증.
5. 블로커 / 리스크
| 항목 | 영향 | 완화책 |
|---|---|---|
| 헬기 콜리전 OFF의 부작용 | 헬기 메시에 좀비가 박히거나, 시야선이 헬기 통과 | 콜리전 프리셋이 Custom: Visibility=Ignore인지 확인. Block 채널은 Pawn만 유지 |
| PartType enum 확장 시 마이그레이션 | 부품 타입 추가하면 모든 DA 인스턴스 재설정 필요 | 오늘은 enum 변경 금지. 신규 타입은 팀플 단계에서 |
| Sweep 우선순위 (슬롯 vs 차량) | 슬롯이 차량 본체 콜리전과 가까우면 시동 분기 진입 안 됨 | 슬롯 InteractionVolume 반경 180 cm가 차량과 겹치는지 PIE에서 측정 |
AStaticMeshActor 후보 컷의 회귀 | 다른 정상 픽업이 SMA 기반이면 같이 차단됨 | AVOIDPickupBase는 AActor 직속 — SMA 아님. PIE에서 픽업 정상 동작 재확인 |
| 시동 분기 미진입 (가장 큰 리스크) | 슬롯 모두 채운 후에도 슬롯 액터가 Sweep에서 우선됨 | EC-5 실측 → 필요 시 슬롯 액터 측에 bInstalled 가드 추가 (코드 수정은 본 문서 범위 밖, 발견 시 별도 커밋) |
| GameMode 위임 미구현 | 시동 성공해도 레벨 전환 안 됨 | 오늘은 로그 출력만 합격 기준. P2로 이월 |
6. 완료 기준 (DoD)
1차 목표 (오늘 반드시)
- §1.1 5단계 모두 PIE 1회로 통과 (스크린샷 또는 Output Log 캡처)
- §1.2 EC-1, EC-4, EC-5, EC-6, EC-7 모두 재현 + 로그 확인
- §1.3 로그 9종 모두 1회 이상 출력 확인
- §3.4 분기 우선순위 실측 표 5행 모두 채움
- 발견 버그 0건 OR 발견 시 별도 메모 (
발견된 버그.md또는 본 문서 §8 디버깅 기록 추가)
2차 목표 (시간 남으면)
- §4 P1 HUD 수리 진행도 ProgressBar 동작
- §4 P2
HandleEscapeSuccess본 구현 +Lv_Escape임시 레벨 전환
3차 목표 (오늘 안 해도 됨, 04-30 이월 가능)
- EC-2b 강제 테스트 (
FindPartByType이 잘못된 부품 반환 시뮬레이션) - EC-3 동작 결정 + 슬롯 액터에
bInstalled가드 추가 여부
7. 참고
8번과제_구현계획.md§B (1227~1290) — 차량 부품 슬롯 인터랙션 원본 설계8번과제_구현계획.md§B (1656~1925) — 헤더/cpp 코드 샘플 (Day 4 작업 시 참조본)2026-04-28_코드리뷰.md— 어제 코드리뷰2026-04-29.md— 오늘 스크럼 (할 일 1번 항목)- graphify Community 1 “아이템 시스템 & 게임 흐름” —
ABaseItem,ASpawnVolume,UDataTable패턴 (참고용, 차량 슬롯은 직접 매핑 안 됨)
8. 디버깅 기록 (작업 중 추가)
PIE 도중 발견 사항을 시간순으로 기록. 새 버그는 본 섹션 추가 후 코드 수정은 별도 커밋.
- (아직 없음 — PIE 진행하며 채울 것)