Youngki Jeong | Game Dev Lab
HomeProjectsEvidenceJourneyAbout
SearchGitHub글쓰기

Youngki Jeong | Game Dev Lab

Unreal C++ 게임개발 포트폴리오 & 개발 기록

Projects·Evidence·Journey·About·GitHub Portfolio·GitHub

빠른 검색

프로젝트, Evidence, 디버깅 노트, 학습 기록을 검색합니다.

← 목록으로
← 목록으로
DX11-B05

BusStop에서 Map Selection과 실제 Map Travel까지

2026년 9월 7일
·
JEONGYOUNGKI
Description

orld Interaction → Map UI → Bus Presentation → Canonical Transition을 하나의 Player-visible Client Flow로 연결한 과정을 정리한 글입니다.

Project

DX11-SpongeBob-BFBB

ArticleType

Integration

SourceBoundary

My Extension

EvidenceLevel

Runtime

Priority

S

Tags

ClientIntegration

ProofType

Runtime

Audience

Technical Interviewer

CareerTrack

Game Client

목차

DX11-B05 | DX11-SpongeBob-BFBB — BusStop에서 Map Selection과 실제 Map Travel까지

한 줄 결론

B05는 Bus Animation 하나를 만든 글이 아니라, World Interaction → Map UI → Destination Validation → Bus Presentation → Canonical Map Transition → Destination Restore를 서로 다른 Client Owner가 순서대로 넘겨받아 하나의 Player-visible Travel Flow로 연결한 과정입니다.

Travel Flow Snapshot

질문답
Map Selection은 어디서 시작하는가?Production에서는 BikiniCity의 World BusStop Interaction에서 시작합니다.
같은 Map을 다시 선택하면 Travel하는가?아니오. UI만 닫고 Bus / Reload / Transition 없이 Gameplay를 계속합니다.
Bus가 Map Transition까지 직접 처리하는가?아니오. Bus는 Presentation만 담당하고 끝나면 기존 CMapTransitionManager로 Handoff합니다.
Player는 Bus 안에서 Destroy되거나 새로 Clone되는가?아니오. Persistent SpongeBob을 유지하고 Presentation 동안 Body / Wand만 Hide합니다.
Transition은 언제 시작하는가?Bus 전체 Mesh가 화면 밖으로 빠져나간 뒤 FinishAndTravel에서 시작합니다.
무엇으로 증명하는가?End-to-End Video + Same-map Negative Video + Owner / Handoff Source 6장

먼저 아래 흐름만 잡으면 B05 전체가 쉽게 읽힙니다.

Text
BusStop
→ Map Selection
→ Destination Validation
→ Bus Presentation
→ Canonical Handoff
→ Destination Restore
→ Gameplay Resume

가장 중요한 책임 경계는 이것입니다.

Text
Bus Presentation
≠
Map Transition

Bus는 Player-facing Presentation을 끝낸 뒤 기존 Canonical Restore 경로에 책임을 넘깁니다.

DX11-SpongeBob-BFBB의 마지막 Player-visible Flow는 하나의 기능만 보여주는 흐름이 아닙니다.

Text
World의 BusStop 접근
→ [E] OPEN MAP
→ Map Selection
→ Destination 선택
→ Bus Presentation
→ Bus가 화면 밖으로 완전히 Exit
→ 기존 Canonical Map Transition으로 Handoff
→ 목적지 Player / Camera / Navigation Restore
→ Gameplay Resume

제가 이 기능에서 중요하게 본 것은 Bus Animation 자체보다 서로 다른 Client System이 어느 시점에 다음 책임으로 넘어가는지 분리해서 연결하는 것이었습니다.

즉 B05의 중심은:

Text
World Interaction
→ UI / Input
→ Destination State
→ Presentation
→ Persistent Player
→ Map Runtime
→ Restore

를 실제 Player가 한 번에 경험할 수 있도록 만드는 것입니다.


🎥 Video 1. BusStop 접근부터 목적지 Gameplay Resume까지 이어지는 End-to-End Production Travel

파일: DX11-B05_Video_01_EndToEnd_BusTravel.mkv

이 영상에서는 다음 흐름이 한 번에 이어지는 것을 확인합니다.

Text
BikiniCity BusStop 접근
→ [E] OPEN MAP
→ E 입력
→ Map Selection Open
→ MapCard Hover
→ 다른 Destination Click
→ Destination Lock
→ UI Close
→ Bus Enter
→ Acceleration / Brake
→ SpongeBob Cover
→ Hold
→ Fast Right Exit
→ Full Exit
→ Canonical Handoff
→ Destination Arrival
→ Player Move

이 영상 하나가 B05 전체에서 가장 중요한 Evidence입니다.

World Interaction부터 UI, Presentation, Map Runtime까지 실제로 연결되어 있다는 점을 한 번에 보여줍니다.


Contribution Boundary

기존 Client에는 이미 다음 구조가 있었습니다.

  • Map Runtime
  • Persistent Player
  • Persistent Camera
  • Map Transition
  • Spawn / Restore

따라서 Map Runtime 전체를 제가 처음부터 만들었다고 설명하지 않습니다.

B05에서 제 작업으로 설명하는 부분은 BusStop Interaction, Map Selection, Destination Validation, Bus Presentation을 기존 Map Runtime과 연결해 하나의 Player-facing Flow로 완성한 부분입니다.

제가 이 프로젝트에서 확장한 부분은 그 위에:

  • BusStop Interaction
  • World-projected Prompt
  • Map Selection UI
  • MapCard State
  • Same-map Guard
  • Bus Travel Presentation
  • Player Presentation Hide
  • Canonical Transition Handoff

를 하나의 Player-facing Flow로 연결한 부분입니다.

특히 Bus Travel은 별도의 Map Transition System이 아닙니다.

Bus Presentation ≠ Map Transition

Bus Presentation이 끝난 뒤 기존 CMapTransitionManager의 Restore 흐름으로 책임을 넘깁니다.

이 경계를 분명하게 잡은 것이 B05 전체의 기준입니다.


시작점은 HUD 버튼이 아니라 World의 BusStop입니다

Production Flow에서 Map Selection은 항상 화면에 떠 있는 Global MAP 버튼으로 여는 구조가 아닙니다.

최종 Production 배치는 다음과 같습니다.

항목현재 기준
MapBikiniCity
Production BusStop Count1
Position(20.5, 0.85, 122.8)

CBusStop Class 자체는 다른 Map에서도 재사용할 수 있도록 만들었지만, Reusable Class라고 해서 모든 Map에 Production Placement가 있다는 뜻은 아닙니다.

현재 Player-facing Production Flow는 BikiniCity에서 시작합니다.

다른 Map에서 Map Selection을 검증할 때는 _DEBUG Shortcut을 사용합니다.

Text
Ctrl + Shift + M
→ Map Selection Toggle

이 경로는 개발 / 검증용입니다.

Production BusStop Flow와 같다고 설명하지 않습니다.

또 _DEBUG Map UI에서 다른 Destination을 선택했을 때는 Bus를 강제로 재생하지 않습니다.

Text
_DEBUG Map UI
→ CommitLockedDestination
→ RequestCanonicalBypassTravel
→ Canonical Transition

즉 Bus는 Production Presentation Layer이고, Map Selection이나 Canonical Transition 자체와 같은 시스템이 아닙니다.


BusStop은 XZ 거리로 Interaction을 판단합니다

Player가 BusStop에 가까워지면 Interaction이 활성화됩니다.

최종 기준은 **Player와 BusStop의 XZ 거리 <= 5.5**입니다.

높이 차이까지 그대로 3D Distance에 넣는 것보다 지면 위에서 실제 접근 거리를 보는 쪽으로 정리했습니다.

이 조건이 World Interaction의 시작점입니다.


[E] OPEN MAP은 World 위치를 따라가는 Prompt입니다

Prompt는 화면의 고정 HUD 위치에 놓인 텍스트가 아닙니다.

BusStop 위에 붙어 있는 것처럼 보여야 했습니다.

Source에서는 다음 흐름을 사용합니다.

Text
BusStop World Position
+ AABB Top
+ Y Offset
→ World-to-UI Projection
→ [E] OPEN MAP

Camera가 움직여도 Prompt가 BusStop의 위치를 따라가야 합니다.

이 작은 기능도 실제로는 World Space → Projection → UI Space를 연결하는 Client Flow입니다.

Prompt 위치가 잘못됐을 때도 Font 좌표만 바로 수정하지 않고:

Text
World Position
→ Bounds Top
→ Projection
→ UI Position

순서로 확인할 수 있습니다.

이 장면은 Video 1 안에서 확인할 수 있으므로 별도 Prompt Screenshot을 반복해서 추가하지 않습니다.


E 입력 이후에만 Map Selection이 Player Flow에 들어옵니다

Production Flow는 다음 순서로 시작합니다.

Text
BikiniCity
→ BusStop 접근
→ Interaction Range
→ [E] OPEN MAP
→ E Input
→ Map Selection Active

Map Selection이 활성화되면 UI가 Input의 중심이 됩니다.

이때 UI 위에 Debug Visualization이 겹쳐 보이지 않도록 일부 Debug 표시를 숨깁니다.

숨기는 Debug 표현실제 Gameplay State
Navigation DebugNavigation 자체는 계속 동작
Player / Wand / Selected Collider DebugCollision 자체는 계속 동작

즉 Debug 표시를 끄는 것과 Gameplay 기능을 끄는 것은 다릅니다.

Presentation과 실제 Gameplay State를 섞지 않도록 구분했습니다.


Map Selection은 여섯 Destination을 같은 Card 규칙으로 다룹니다

최종 Map Selection에는 여섯 Destination이 있습니다.

  • SpongeBobHouseInner
  • BikiniCity
  • SandyHouse
  • KrustyKrabInner
  • JellyFields
  • ChumBucketInner

C++ 구조는 공통 Base와 Destination별 Class로 정리했습니다.

Text
CUI_MapCard_Base
→ CUI_MapCard_SpongeBobHouseInner
→ CUI_MapCard_BikiniCity
→ CUI_MapCard_SandyHouse
→ CUI_MapCard_KrustyKrabInner
→ CUI_MapCard_JellyFields
→ CUI_MapCard_ChumBucketInner

UI_Map_Button_* 이름은 별도의 두 번째 GameObject Class Family가 아니라 Texture Asset Naming에 사용합니다.

구분의미
C++ ClassMapCard
TextureUI_Map_Button_<Map>_Gray / Color

최종 화면 Stack도 실제 Runtime에 사용하는 요소만 남겼습니다.

Text
UI_Map_Background_Map
→ UI_Map_Window
→ UI_Map_Background_Road_Overlay
→ six MapCards
→ UI_Map_Title
→ UI_Map_Close

프로젝트 파일에 Legacy Presentation Class나 Resource가 남아 있을 수 있지만, 프로젝트 파일에 존재하는 것과 현재 Runtime에서 실제 사용하는 것은 다릅니다.


MapCard는 Idle / Hover / Click을 나눴습니다

각 MapCard는 복잡한 State Machine보다 Player Feedback이 명확하게 보이는 정도로 정리했습니다.

State표현 / 역할
IdleGray
HoverColor
ClickColor + Short Pulse + SFX + Destination Lock

Click Pulse는 Authoring Size 자체를 바꾸는 값이 아닙니다.

Authored Layout Size ≠ Transient Click Pulse

Hover는 “선택 가능하다”는 Feedback이고, Click은 “선택됐다”는 Feedback입니다.

Destination을 Lock한 뒤에는 이후 중복 입력이 Presentation Flow를 다시 흔들지 않도록 합니다.

이 세부 장면도 Video 1 안에서 확인할 수 있으므로 Gray / Color 비교 Screenshot을 별도로 반복하지 않습니다.


같은 Map을 선택하면 Travel하지 않습니다

MapCard Click이 항상 Bus Travel을 시작하는 것은 아닙니다.

현재 Map과 같은 Destination을 고르면:

Text
Same Destination
→ Map UI Close
→ NO Bus
→ NO Map Reload
→ NO Transition
→ Gameplay Continue

로 끝냅니다.

즉 Same Destination ≠ Travel Request입니다.

이미 같은 Map에 있는데 Bus Presentation과 Map Restore를 다시 실행할 이유가 없기 때문입니다.

이 Negative Path는 단순한 예외처리가 아니라 Destination Validation을 한 뒤 필요한 경우에만 다음 책임으로 넘어간다는 Contract를 보여줍니다.


🎥 Video 2. 같은 Destination을 선택하면 UI만 닫히고 Travel하지 않는 Negative Path

파일: DX11-B05_Video_02_SameMap_NoTravel.mkv

현재 Map과 같은 MapCard 선택 → UI Close → Bus 없음 → Reload 없음 → Transition 없음 → Gameplay 계속까지 보여줍니다.

길게 찍을 필요는 없습니다.

Text
Same Destination Click
→ UI Close
→ No Bus
→ Same Gameplay Continues

가 분명하게 보이면 충분합니다.

B05에서 이 영상은 Flow에 Validation Contract가 있다는 점을 보여주는 두 번째 핵심 Evidence입니다.


다른 Destination은 Production Bus Presentation으로 이어집니다

BikiniCity BusStop으로 연 Production Map Selection에서 다른 Destination을 고르면 Bus Presentation을 시작합니다.

Text
Different Destination
→ Click Feedback
→ Destination Lock
→ Map UI Close
→ Bus Enter
→ Cover
→ Hold
→ Exit
→ Canonical Handoff

반면 _DEBUG Ctrl + Shift + M으로 연 Map UI는 같은 Destination 선택 규칙을 가지지만, 다른 Destination이면 Bus 없이 Canonical Transition으로 바로 넘길 수 있습니다.

경로Different Destination 선택
ProductionBus Presentation → Canonical Handoff
_DEBUGBus-less Handoff

따라서 Different Destination이면 항상 Bus가 나온다고 일반화하지 않습니다.


Bus는 Enter / Hold / Exit를 나눠서 만들었습니다

Production Bus Sequence는 다음처럼 이어집니다.

Text
Destination Lock
→ UI Close
→ Enter
→ Acceleration
→ Sharp Brake
→ Cover
→ Body / Wand Hide
→ Hold 2.0 sec
→ Rapid Right Exit
→ Entire Mesh Out
→ FinishAndTravel

여기서 가장 중요한 것은 Map Transition이 Bus Presentation보다 먼저 시작하지 않는 것입니다.

Player 입장에서는 Bus가 SpongeBob을 태우고 실제로 화면을 빠져나간 뒤 다음 Map으로 넘어가야 자연스럽습니다.


Bus Facing은 Travel Axis 기준 +85°로 고정했습니다

Bus는 이동하면서 매 Frame Player를 바라보지 않습니다.

현재 기준은:

항목값
Yaw+85°
AxisWorld +Y
ReferenceTravel Axis
Enter / Hold / ExitSame Facing
Per-frame LookAt사용하지 않음
Z Roll사용하지 않음

매 Frame LookAt을 적용하면 Enter / Hold / Exit 동안 방향이 계속 흔들릴 수 있어서 이 Presentation에서는 고정 Facing을 사용했습니다.

초기 +75°에서 +85°로 바꾼 내용은 Tuning 과정이고, 현재 기준은 +85°입니다.


Enter는 빠르게 접근하고 Cover Position에서 급제동합니다

Enter 시간은 최종적으로 약 1.45 sec입니다.

연출 의도는:

Text
빠르게 접근
→ SpongeBob 근처에서 급제동
→ Cover Position 정차

였습니다.

과거에 72% / 78% 같은 Curve Tuning 기록도 있지만, 그 숫자를 최종 Contract처럼 사용하지 않습니다.

현재 설명에서 중요한 것은 정확한 비율보다 Bus가 빠르게 들어오고 SpongeBob 앞에서 확실하게 멈추는 Player-visible Result입니다.


SpongeBob은 Bus가 실제로 Cover한 뒤에 숨깁니다

Player Hide Timing도 Bus State와 맞췄습니다.

Bus가 아직 SpongeBob에게 오지도 않았는데 Player가 먼저 사라지면 Presentation이 깨집니다.

그래서 순서는 다음과 같습니다.

Text
Bus Enter 중
→ SpongeBob Visible
 
Bus가 Cover Position 도달
→ Body Hide
→ Wand Hide
→ Hold

즉 Player가 먼저 사라지는 것이 아니라, Bus가 SpongeBob을 가린 뒤 Body / Wand를 숨깁니다.

그리고 여기서 Player Object를 Destroy하는 것도 아닙니다.

Bus용 Player를 새로 Clone하지도 않습니다.

Presentation Hide ≠ Player Destroy

Persistent SpongeBob = 유지

이 경계를 유지했기 때문에 Presentation이 끝난 뒤 기존 Persistent Player를 그대로 B04의 Canonical Restore로 넘길 수 있습니다.


Hold는 2초로 두었습니다

Bus가 Cover Position에 도착한 뒤 바로 출발하지 않습니다.

Hold = 2.0 sec입니다.

이 짧은 정지 시간은 Player가:

Text
Bus가 도착함
→ SpongeBob을 태움
→ 다시 출발함

이라는 연출을 인지할 시간을 주기 위한 값입니다.

따로 Hold 영상까지 만들 필요는 없습니다.

Video 1의 End-to-End Flow에 포함시키는 것으로 충분합니다.


Exit는 Fade 없이 오른쪽으로 완전히 빠져나갑니다

Hold 이후 Bus는 빠르게 오른쪽으로 나갑니다.

최종 Exit 시간은 약 1.15 sec입니다.

Text
Hold End
→ Rapid Acceleration
→ Right Exit
→ Entire Mesh Outside Screen
→ Presentation Complete
→ Canonical Travel

이 연출에서는 Alpha Fade를 사용하지 않습니다.

No Fade이며, 실제 Mesh가 화면 밖으로 완전히 빠져나간 뒤에 Travel을 시작합니다.

Full Exit → Then Travel

이 순서를 지키는 것이 화면상 전환 완성도에 영향을 줬습니다.


Bus Presentation이 끝난 뒤 기존 Map Runtime으로 책임을 넘깁니다

B05에서 가장 중요하게 보여주고 싶은 Source Flow입니다.

Bus Presentation의 마지막 단계는 새로운 Map Loader를 직접 호출하는 것이 아닙니다.

현재 Production Flow는:

Text
FinishAndTravel
→ RequestCanonicalBypassTravel
→ RequestTransition(
    Target,
    L"",
    L"",
    true
)

로 이어집니다.

여기서부터는 B04에서 정리한 CMapTransitionManager의 Canonical Restore가 책임을 가집니다.

Text
Target Map Resolve
→ Map-scoped Content
→ Navigation
→ Player Spawn Resolution
→ Persistent SpongeBob Relocate
→ Transient Reset
→ Camera Restore
→ Gameplay Resume

B05의 Bus Feature가 이 Restore를 다시 구현하지 않습니다.

Owner를 나누면 다음과 같습니다.

Owner책임
CBusStopWorld Interaction
CUI_MapCard_BaseDestination Selection / Validation
CBusTravelPresenterProduction Presentation
Persistent SpongeBobPlayer Lifetime 유지
RequestCanonicalBypassTravelPresentation / Transition Boundary
CMapTransitionManagerMap Spawn / Restore

🔡 Source 1A~1F. BusStop → MapCard → Bus Presenter → Canonical Handoff

Owner / Handoff 흐름은 World Interaction → Validation → Destination Commit → Presentation Complete → Travel Handoff → Canonical Transition의 여섯 단계로 나눠 읽습니다.

전체 흐름은 다음 하나입니다.

Text
CBusStop
→ Map UI Open
 
CUI_MapCard_Base
→ Click / Same-map Validation
 
CBusTravelPresenter
→ Destination Commit
→ Bus Exit
→ FinishAndTravel
 
RequestCanonicalBypassTravel
→ CMapTransitionManager

이 여섯 장의 목적은 “코드가 많다”는 것을 보여주는 것이 아니라, 각 Owner가 자기 책임을 끝내고 다음 Owner에게 언제 넘기는지를 읽게 하는 것입니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff0_BusStop_OpenMap.png

Source 1A — BusStop → Open Map

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff0_BusStop_OpenMap.png

World의 CBusStop Interaction이 Map Selection을 여는 첫 Handoff를 보여줍니다.

Text
Player 접근
→ Interaction Gate
→ E Input
→ Open Map

이 장의 핵심 질문:

“Player-facing Travel Flow는 어디서 시작되는가?”

Production에서는 HUD의 Global MAP 버튼이 아니라 World BusStop Interaction이 시작점입니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff1_MapCard_Click.png

Source 1B — MapCard Click / Same-map Guard

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff1_MapCard_Click.png

MapCard Click에서 현재 Map과 선택 Destination을 비교하고, 같은 Map이면 Travel을 시작하지 않는 Validation 경계를 보여줍니다.

Text
MapCard Click
→ Current Map 비교
 
Same Destination
→ UI Close
→ No Bus
→ No Transition

즉:

Text
MapCard Click
≠
항상 Travel

입니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff2_NotifyCardClicked.png

Source 1C — Destination Commit

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff2_NotifyCardClicked.png

다른 Destination이 선택된 뒤 Presenter가 선택 결과를 받아 Destination을 확정하고 Presentation을 준비하는 경계를 보여줍니다.

Text
Different Destination
→ NotifyCardClicked
→ Destination Lock
→ Click Feedback / UI Close
→ Bus Presentation 준비

여기서 중요한 것은 MapCard가 Map Runtime을 직접 수행하지 않고, 선택 결과를 다음 Owner에게 넘긴다는 점입니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff3A_Tick_BusExit_To_Finish.png

Source 1D — Bus Exit → Finish 조건

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff3A_Tick_BusExit_To_Finish.png

CBusTravelPresenter::Tick에서 Bus Exit Phase를 진행하고, Presentation이 완료된 시점에 FinishAndTravel로 넘어가는 경계를 보여줍니다.

Text
Bus Exit
→ Progress
→ Full Exit
→ Presentation Complete
→ FinishAndTravel

이 장이 B05에서 특히 중요한 이유는:

Map Transition이 Bus가 화면을 빠져나가기 전에 시작되지 않는다

는 Presentation Contract를 Source에서 연결하기 때문입니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff3B_FinishAndTravel.png

Source 1E — FinishAndTravel

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff3B_FinishAndTravel.png

Presentation을 정리하고 실제 Travel 요청으로 책임을 넘기는 Handoff입니다.

Text
FinishAndTravel
→ Presentation State 정리
→ RequestCanonicalBypassTravel(Target)

Bus Presenter의 책임은 여기까지입니다.

새 Map을 직접 Load하거나 Player Restore를 다시 구현하지 않습니다.

DX11-B05_Screenshot_01_Source_Owner_Handoff4_RequestCanonicalBypassTravel.png

Source 1F — Canonical Transition Handoff

파일: DX11-B05_Screenshot_01_Source_Owner_Handoff4_RequestCanonicalBypassTravel.png

마지막으로 RequestCanonicalBypassTravel이 기존 CMapTransitionManager에 Transition을 요청하는 경계를 보여줍니다.

현재 흐름은 다음 의미로 이어집니다.

Text
RequestCanonicalBypassTravel(Target)
→ RequestTransition(
    Target,
    L"",
    L"",
    true,
    ...
)
→ CMapTransitionManager

이 지점부터는 B04에서 정리한 Canonical Restore가 책임을 가집니다.

Text
Target Resolve
→ Spawn Resolution
→ Persistent Player Relocate
→ Navigation / Camera Restore
→ Gameplay Resume

여섯 장을 한 문장으로 읽으면

World Interaction은 CBusStop, Destination Validation은 CUI_MapCard_Base, Production 연출은 CBusTravelPresenter, 실제 Map Restore는 CMapTransitionManager가 담당하며 각 단계가 명시적으로 다음 Owner에게 책임을 넘깁니다.

이 B05 Source Evidence에는 별도 Debugger / Watch를 억지로 추가하지 않습니다. 여기서는 Runtime 숫자보다 Owner / Responsibility / Handoff 구조가 핵심이고, 실제 결과는 Video 1과 Video 2가 더 직접적인 Evidence입니다.


BACK / ESC도 정상 Flow입니다

Map UI를 열었다고 반드시 Destination을 선택해야 하는 것은 아닙니다.

Text
Open Map
→ BACK / ESC
→ Close
→ No Bus
→ No Transition
→ Gameplay Return

경로도 있습니다.

BACK 쪽 Source 책임은 다음처럼 나뉩니다.

Owner책임
CBusTravelPresenterBACK Input Authority
CUI_Map_CloseVisual / Layout Owner

B03에서 UI Layout을 수정할 때 BACK의 Visual Rect와 Hit Rect가 같은 Runtime Layout State를 읽는 이유도 여기와 연결됩니다.

BACK / ESC는 별도 세 번째 Negative Video로 반복하기보다, Same-map Negative를 대표 Negative Evidence로 사용하고 필요할 때 Deep Dive로 설명합니다.


문제가 생기면 Owner 경계부터 확인합니다

B05는 여러 System이 연결된 기능이라 문제가 생기면 마지막 화면만 보지 않고 Owner 경계를 따라 확인합니다.

증상확인 순서
Prompt가 안 보임BusStop 존재 → XZ Distance → Interaction Gate → Projection → Font
Map UI가 안 열림E Input → Interaction Range → UI Active
Hover가 안 바뀜Mouse → Hit Rect → Hover State → Texture
Card를 눌렀는데 Bus가 안 나옴Same Map? → Production Flow? → _DEBUG Flow?
Player가 너무 빨리 숨음Enter Phase → Cover Position → Hide Timing
Bus가 화면에 남았는데 Map이 바뀜Exit → Entire Mesh Out → FinishAndTravel → Handoff

Destination은 맞는데 Player / Camera가 이상하다면 그 시점부터 B05 Presentation이 아니라 B04 Canonical Restore를 봅니다.

Text
RequestCanonicalBypassTravel
→ RequestTransition(Target, L"", L"", true)
→ ResolvePlayerSpawnForPending

으로 System Boundary를 넘기기 때문입니다.


일부러 만들지 않은 것도 있습니다

최종 구현에서는 기능 개수를 계속 늘리는 대신 지금 Flow를 닫는 쪽을 선택했습니다.

다음 기능은 현재 Production Flow에 넣지 않았습니다.

  • 모든 Map에 Production BusStop
  • Global MAP HUD
  • 새로운 Map Transition System
  • Bus용 Player Clone
  • Bus용 Camera System
  • Early Fade
  • Per-frame LookAt

관련 없는 Sound Asset을 억지로 Brake SFX라고 붙이지도 않았습니다.

Feature Count보다 현재 Player Flow를 안정적으로 닫는 쪽을 우선했습니다.


Current Source와 Runtime 결과도 구분합니다

Current Source에서 직접 확인할 수 있는 범위는 다음과 같습니다.

항목Current Source 기준
Production BusStopBikiniCity 1개
InteractionXZ <= 5.5
PromptWorld-projected [E] OPEN MAP
MapCard6 Destination
Same MapClose Only
Production BusEnter / Hold / Exit
Facing+85°
CoverBody / Wand Hide
Hold2.0 sec
ExitNo Fade / Full Right Exit
HandoffFinishAndTravel → RequestCanonicalBypassTravel
_DEBUGBus-less Canonical Handoff

Current Source가 존재하는 것과 Runtime Result가 확인되는 것은 같은 증거가 아닙니다.

B05에서는 두 Runtime Video를 별도 Evidence로 사용합니다.

Text
Video 1
→ End-to-End Production Travel
 
Video 2
→ Same-map Negative

Source는 Owner / Handoff 구조를 설명하고, Video는 Player-visible Result를 담당합니다.

기능별 Git Commit Hash가 확인되지 않은 부분에는 임의 Hash를 붙이지 않습니다.


B05 Evidence Map — 각 자료가 맡는 질문

B05의 Evidence는 역할 기준으로 세 묶음입니다.

Text
End-to-End Runtime
Negative Path
Owner / Handoff Source

실제 파일은 Source Handoff를 단계별로 나눠 총 8개입니다.

면접관이 먼저 Runtime 결과를 보고, 필요할 때 Source로 내려갈 수 있게 배치합니다.

Runtime Evidence — 2개

역할실제 파일이 자료가 닫는 질문
End-to-End TravelDX11-B05_Video_01_EndToEnd_BusTravel.mkvBusStop → Map UI → Bus → Transition → Destination Gameplay가 실제로 한 흐름으로 이어지는가?
Same-map NegativeDX11-B05_Video_02_SameMap_NoTravel.mkv같은 Destination에서는 불필요한 Bus / Reload / Transition을 막는가?

Owner / Handoff Source — 6개

역할실제 파일이 자료가 닫는 질문
BusStop → Open MapDX11-B05_Screenshot_01_Source_Owner_Handoff0_BusStop_OpenMap.pngProduction Player Flow는 어느 World Interaction에서 시작되는가?
MapCard ValidationDX11-B05_Screenshot_01_Source_Owner_Handoff1_MapCard_Click.pngSame-map을 어디에서 막고 Different Destination을 어디서 구분하는가?
Destination CommitDX11-B05_Screenshot_01_Source_Owner_Handoff2_NotifyCardClicked.png선택된 Destination을 어떻게 Lock하고 Presentation으로 넘기는가?
Bus Exit → FinishDX11-B05_Screenshot_01_Source_Owner_Handoff3A_Tick_BusExit_To_Finish.pngBus Presentation이 언제 완료됐다고 판단하는가?
Finish / TravelDX11-B05_Screenshot_01_Source_Owner_Handoff3B_FinishAndTravel.pngPresentation Owner는 어디서 자신의 책임을 끝내는가?
Canonical HandoffDX11-B05_Screenshot_01_Source_Owner_Handoff4_RequestCanonicalBypassTravel.png기존 Map Transition / Restore 시스템으로 어디서 책임을 넘기는가?

가장 쉬운 읽기 순서

Text
① End-to-End Video
전체 Player Experience를 먼저 본다
 
→ ② Same-map Video
Negative Contract를 본다
 
→ ③ BusStop OpenMap
World Interaction 시작점
 
→ ④ MapCard Click
Destination Validation
 
→ ⑤ NotifyCardClicked
Destination Commit
 
→ ⑥ Tick BusExit → Finish
Presentation 완료 조건
 
→ ⑦ FinishAndTravel
Presentation → Travel Handoff
 
→ ⑧ RequestCanonicalBypassTravel
Canonical Map Runtime으로 최종 책임 이동

이 순서의 장점은 Source를 먼저 읽지 않아도:

Text
무슨 기능인가
→ 어떤 예외를 막는가
→ 누가 어떤 책임을 갖는가
→ 어디서 기존 Runtime으로 넘기는가

가 자연스럽게 보인다는 점입니다.


게임 클라이언트 관점에서 이 Flow가 중요한 이유

B05처럼 여러 System이 연결된 기능은 마지막 결과만 보면 원인 Owner를 찾기 어렵습니다.

Owner 경계를 나누면 문제를 빠르게 좁힐 수 있습니다.

Text
Prompt가 안 보임
→ BusStop / Interaction / Projection
 
Map UI가 안 열림
→ Input / UI Activation
 
같은 Map인데 Travel함
→ MapCard Validation
 
Bus가 안 나옴
→ Production / _DEBUG Path 구분
 
Bus는 끝났는데 Travel이 안 됨
→ FinishAndTravel / Canonical Handoff
 
도착 후 Player / Camera가 이상함
→ B05가 아니라 B04 Restore 영역

즉 B05의 핵심은 연출 기능 자체보다 어느 Owner가 언제 다음 Owner에게 책임을 넘기는지 설명하고 디버깅할 수 있다는 점입니다.


면접에서 30초로 설명한다면

“Production Travel은 BikiniCity의 BusStop Interaction에서 시작합니다. MapCard에서 같은 Map인지 먼저 검증하고, 같은 Map이면 UI만 닫고 Travel하지 않습니다. 다른 Destination이면 선택 결과를 Presenter로 넘기고, Bus Presenter가 Enter / Hold / Exit 연출을 담당합니다. Bus가 화면 밖으로 완전히 빠져나간 뒤 FinishAndTravel에서 RequestCanonicalBypassTravel을 호출하고, 그 시점부터는 기존 CMapTransitionManager의 Canonical Restore가 Player / Navigation / Camera 복원을 담당합니다. 즉 Bus를 새로운 Map Transition System으로 만들지 않고 World / UI / Presentation / Restore의 책임을 분리했습니다.”

이 답변의 핵심은:

Text
Bus가 모든 것을 처리
X
 
World Interaction
→ UI Validation
→ Presentation
→ Canonical Transition
→ Restore
O

입니다.


정리

B05의 Player-visible Flow를 가장 짧게 줄이면 다음과 같습니다.

Text
BusStop
→ Map Selection
→ Destination Validation
→ Bus Presentation
→ Canonical Handoff
→ Destination Restore
→ Gameplay Resume

하지만 실제 Client 관점에서는 각 단계의 Owner가 다릅니다.

Owner책임
BusStopWorld Interaction
MapCardDestination Selection / Validation
Bus PresenterProduction Presentation
Persistent SpongeBobPlayer Lifetime
MapTransitionManagerMap State Restore

제가 이 기능을 만들면서 중요하게 본 것은 Bus 하나를 움직이는 것이 아니었습니다.

  • 언제 UI가 Input을 가져가는지
  • 언제 Destination을 Lock하는지
  • Same Map에서는 왜 Travel하지 않는지
  • 언제 Player를 숨기는지
  • 언제 Presentation이 끝났다고 볼지
  • 어느 시점에 기존 Map Runtime으로 책임을 넘길지

를 각각 나누고, 그 결과를 하나의 Player Experience로 연결하는 것이었습니다.

새 Map Transition System을 하나 더 만들지 않고 기존 Canonical Restore를 재사용하면서 Production과 Debug 경로도 구분했습니다.

Text
Production
World Interaction
→ Map UI
→ Bus Presentation
→ Canonical Handoff
→ Restore
 
_DEBUG
Map UI
→ Bus-less Handoff
→ Restore

이 글까지가 DX11-SpongeBob-BFBB 공개 시리즈의 마지막입니다.

빠른 검색

프로젝트, Evidence, 디버깅 노트, 학습 기록을 검색합니다.

목차