Youngki Jeong | Game Dev Lab
HomeProjectsEvidenceJourneyAbout
SearchGitHub글쓰기

Youngki Jeong | Game Dev Lab

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

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

빠른 검색

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

← 목록으로
← 목록으로
DX11-B03

Runtime에서 편집한 Object와 UI를 다시 복원하기까지

2026년 9월 7일
·
JEONGYOUNGKI
Description

Runtime Object와 UI Layout을 직접 편집하고 파일을 거쳐 다시 Runtime State로 복원하는 Tooling과 Persistence 구조를 정리한 글입니다.

Project

DX11-SpongeBob-BFBB

ArticleType

Tooling

SourceBoundary

My Extension

EvidenceLevel

Runtime

Priority

S

Tags

Tooling

ProofType

Runtime

Audience

Technical Interviewer

CareerTrack

Game Client

목차

DX11-B03 | DX11-SpongeBob-BFBB — Runtime에서 편집한 Object와 UI를 다시 복원하기까지

한 줄 결론

Runtime Tool의 핵심은 ImGui 창 자체가 아니라, Tool에서 바꾼 값이 실제 Runtime State를 수정하고, 그 State가 저장된 뒤 다시 같은 Runtime 의미로 복원되는가에 있습니다.

Runtime Tooling Snapshot

질문답
Scene Object와 UI Layout은 같은 Save / Load인가?아니오. Scene Object는 Runtime Reconstruction, UI Layout은 Existing Runtime UI State Update입니다.
Scene Object 저장에서 Pointer를 저장하는가?아니오. Prototype / Layer Identity와 Transform State를 저장합니다.
Tool에서 배치한 Object는 Editor 전용 Object인가?아니오. 기존 Runtime Spawn Path를 사용하는 실제 Runtime Object입니다.
UI Layout Load는 새 UI를 Spawn하는가?아니오. Stable Identity로 기존 Runtime UI를 찾아 Layout State만 갱신합니다.
Rotation은 어떻게 저장하는가?Runtime의 radian을 file의 degree로 저장하고 Load 시 다시 radian으로 변환합니다.
무엇으로 증명하는가?Scene / UI Roundtrip Video + Persistence Source Flow

먼저 아래 두 흐름만 잡으면 뒤의 구현 차이가 쉽게 보입니다.

Text
Scene Object
Identity + Transform
→ File
→ Runtime Reconstruction
 
UI Layout
Stable UI Identity + Layout State
→ File
→ Existing Runtime UI Update

둘 다 “Save / Load”라고 부르지만 대상의 Lifetime과 State Owner가 다르기 때문에 Load의 의미도 다릅니다.

DX11-SpongeBob-BFBB의 Runtime Tooling에서 가장 중요하게 본 것도 ImGui 창 자체가 아니라, Tool Input이 실제 Runtime State를 바꾸고 그 State가 저장된 뒤 다시 같은 Runtime 의미로 돌아오는가였습니다.

프로젝트에는 크게 두 가지 Authoring 흐름이 있습니다.

Text
Scene Object Authoring
 
Prototype / Layer 선택
→ World Picking
→ Runtime Spawn
→ Position / Scale / Rotation 수정
→ ObjectsSaved.txt
→ Load
→ Runtime Clone Reconstruction
Text
UI Layout Authoring
 
Existing Runtime UI
→ Direct Select
→ Drag / Resize
→ Runtime Layout State
→ UiLayout.txt
→ Stable Identity Lookup
→ Existing Runtime UI Update

둘 다 Save / Load라는 이름을 사용하지만 Runtime에서 의미는 다릅니다.

대상Load의 의미
Scene Object저장된 Identity / State를 읽어 Runtime Object를 다시 구성
UI Layout이미 존재하는 Runtime UI를 찾아 Layout State만 갱신

이 차이를 구분하는 것이 B03의 핵심입니다.


Contribution Boundary

ImGui는 Tool UI Framework로 사용했습니다.

따라서 ImGui 자체를 구현했다고 설명하지 않습니다. 이 글에서 제 작업으로 설명하는 부분은 Object Spawn / Transform 편집 / Save·Load와 UI Layout 편집을 실제 Runtime State와 연결한 프로젝트용 Authoring / Persistence Flow입니다.

Tool UI가 있다고 Runtime Tool이 되는 것은 아니었습니다

Tool에 버튼과 Transform 입력창이 있다는 것만으로 실제 게임 Runtime과 연결됐다고 보지는 않았습니다.

확인해야 할 흐름은 다음과 같습니다.

Text
Tool Input
→ Real Runtime State Change
→ Player-visible Result
→ Serializable State
→ File
→ Load
→ Runtime Apply
→ Player-visible Result

즉 Tool UI가 존재하는 것, Runtime State가 실제로 바뀌는 것, Disk에 저장되는 것은 각각 다른 단계입니다.

Tool에서 값을 바꿨다면 실제 Object나 UI가 그 값을 소유해야 하고, 저장했다면 다음 실행에서도 다시 해석할 수 있는 Identity와 State가 남아야 했습니다.


Scene Object Tool

별도의 Editor Object를 만들지 않고 실제 Runtime Spawn Path를 사용했습니다

Scene Object를 배치할 때는 Prototype과 Layer를 선택하고 World Picking으로 위치를 얻습니다.

그 결과는 별도의 Editor 전용 Object System으로 가지 않고 기존 Runtime Spawn 경로로 들어갑니다.

Text
Prototype 선택
→ Layer 선택
→ World Picking
→ World Position
→ CObject_Manager::Add_GameObject_ToLayer
→ Runtime Clone
→ Layer 삽입
→ Update / Render

즉 Tool에서 보이는 Object와 실제 게임 Object를 따로 두지 않았습니다.

Tool에서 배치한 Object = 실제 Runtime Object

이 때문에 Tool에서 생성한 Object도 기존 Layer의 Update / Collision / Render 흐름에 그대로 참여합니다.


Picking 결과도 실제 Runtime Transform에 적용됩니다

Tool에서 필요한 것은 화면의 2D Mouse 좌표가 아니라 실제 World Position입니다.

Text
Mouse Input
→ Picking
→ World Position
→ GAMEOBJECT_DESC
→ Runtime Spawn
→ CTransform

Spawn 이후 Position / Scale / Rotation을 수정할 때도 별도의 Editor Transform을 하나 더 두지 않았습니다.

역할Owner
WriterEditor
State OwnerRuntime Object
ReaderRender / Collision

Tool에서 값을 바꾸면 실제 Runtime Object의 Transform이 바로 바뀌고, Render와 Collision도 같은 State를 읽습니다.


Save할 때는 Pointer가 아니라 다시 만들 수 있는 Identity와 State를 남깁니다

Runtime Pointer는 실행 중에만 의미가 있습니다.

그래서 ObjectsSaved.txt에는 Pointer Address가 아니라 Object를 다시 구성할 수 있는 정보를 저장합니다.

저장 정보목적
Prototype / Type Identity어떤 Object를 다시 만들지 식별
Layer어느 Runtime Container에 넣을지 식별
Position위치 복원
Scale크기 복원
Rotation XYZ회전 복원

즉 Pointer 자체를 저장하는 것이 아니라 Identity + State를 저장합니다.

현재 저장 Format에서는 Position / Scale뿐 아니라 Rotation도 함께 다룹니다.


Rotation은 Runtime과 파일의 단위를 나눴습니다

Runtime Transform은 radian 계열 값을 사용하지만, 텍스트 파일에는 사람이 확인하기 쉬운 degree 값으로 저장합니다.

Text
Save
Runtime Rotation(rad)
→ RadiansToDegrees
→ ObjectsSaved.txt(deg)
 
Load
ObjectsSaved.txt(deg)
→ DegreesToRadians
→ Runtime Rotation(rad)

이 대칭이 맞아야 Position / Scale은 정상인데 Rotation만 다르게 복원되는 문제를 피할 수 있습니다.


예전 Row에 Rotation이 없어도 읽을 수 있게 했습니다

기존 저장 데이터에는 Rotation 값이 없는 Row도 있었습니다.

새 Format만 강제로 요구하면 예전 Map Data를 다시 사용할 수 없기 때문에 Rotation Field가 없는 경우에는 기본값을 사용하도록 처리했습니다.

Format읽는 값
Old RowPrototype / Layer / Position / Scale → Rotation은 (0, 0, 0)
New RowPrototype / Layer / Position / Scale / Rotation XYZ

거창한 Versioning System이라기보다, 기존 데이터와 새 Transform State를 같이 사용할 수 있게 만든 작은 호환 처리입니다.


File Parser와 Runtime Spawn Owner도 분리했습니다

파일을 읽는 함수가 직접 Object까지 Spawn한다고 보면 실제 책임이 섞입니다.

Scene Object Load는 다음처럼 이어집니다.

Text
ObjectsSaved.txt
→ LoadObjectStates
→ vector<GameObjectState>
→ CMainApp Load / Spawn Loop
→ GAMEOBJECT_DESC
→ Add_GameObject_ToLayer
→ Runtime Clone
→ Loaded Transform Apply

역할을 나누면:

단계책임
LoadObjectStatesFile Parse
CMainApp Spawn LoopRuntime Reconstruction
ApplyLoadedObjectTransform저장된 Transform을 Runtime Instance에 적용

Load에서도 별도의 Tool 전용 Spawn System을 만들지 않고 B01에서 정리한 기존 Runtime Spawn Path를 다시 사용합니다.

결국 저장 데이터는 Pointer를 되살리는 정보가 아니라 기존 Runtime Path를 다시 실행하기 위한 Identity와 State입니다.


🎥 Video 1. MapTool에서 Object를 배치하고 Save → Reload로 같은 Transform을 복원

파일: DX11-B03_Video_01_MapTool_SaveLoad_Restore.mkv

Prototype / Layer 선택 → Platform 배치 → Position / Scale / Rotation 수정 → Save → Reload → 같은 Transform 복원까지 한 번에 보여줍니다.

B03에서 가장 중요한 Scene Object Runtime Evidence입니다.

단순히 Save 버튼을 누르는 장면이 아니라 다음 흐름이 한 영상에서 닫혀야 합니다.

Text
Runtime Spawn
→ Real Transform Edit
→ Serialize
→ Reload
→ Runtime Reconstruction

영상 안에서 ObjectsSaved.txt의 저장 Row를 잠깐 보여주면 별도의 Data Screenshot을 본문에 추가하지 않아도 충분합니다.


🔡 Source 1A~1F. Scene Object Persistence — Save → Parse → Reconstruction → Transform Apply

Scene Object Persistence는 Save Schema → File Write → Parse → Compatibility → Reconstruction → Transform Apply의 여섯 단계로 나눠 읽습니다.

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

Text
Runtime Object State
→ Save Schema
→ File Write
→ Load Parse
→ Rotation Compatibility
→ Runtime Reconstruction
→ Transform Apply
DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0A_SaveObjectStates_Schema.png

Source 1A — Save Schema

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0A_SaveObjectStates_Schema.png

저장할 때 Runtime Pointer 자체가 아니라 다시 구성할 수 있는 Identity + State를 남기는 구조를 보여줍니다.

Text
Prototype / Type Identity
+ Layer
+ Position
+ Scale
+ Rotation
→ Serializable State

이 장의 핵심 질문은:

“무엇을 저장해야 다음 실행에서 같은 종류의 Object를 다시 만들 수 있는가?”

입니다.

DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0B_SaveObjectStates_Write.png

Source 1B — Save Write

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0B_SaveObjectStates_Write.png

수집한 Object State가 실제 파일 기록으로 이어지는 경계를 보여줍니다.

Text
Runtime State
→ Serializable State
→ ObjectsSaved.txt

여기서 Rotation은 사람이 확인하기 쉬운 degree 의미로 저장하는 흐름과 연결됩니다.

DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1A_LoadObjectStates_Parse.png

Source 1C — Load Parse

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1A_LoadObjectStates_Parse.png

ObjectsSaved.txt를 읽어 GameObjectState로 복원하는 Parse 경계입니다.

Text
ObjectsSaved.txt
→ Parse
→ GameObjectState

파일을 읽었다는 사실과 Runtime Object가 다시 생성됐다는 사실은 아직 같은 단계가 아닙니다.

DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1B_LoadObjectStates_RotationCompatibility.png

Source 1D — Rotation Compatibility

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1B_LoadObjectStates_RotationCompatibility.png

예전 저장 Row에 Rotation Field가 없더라도 읽을 수 있도록 한 호환 처리를 보여줍니다.

Text
Old Row
→ Rotation 없음
→ Default (0, 0, 0)
 
New Row
→ Rotation XYZ 존재
→ Parsed Rotation 사용

이 처리는 범용 Versioning System이라고 과장하지 않고, 기존 Data와 새 Transform State를 함께 사용할 수 있게 한 작은 호환 경계로 설명합니다.

DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2A_RuntimeReconstruction.png

Source 1E — Runtime Reconstruction

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2A_RuntimeReconstruction.png

Parse된 State가 다시 실제 Runtime Spawn Path로 들어가는 구간입니다.

Text
Parsed GameObjectState
→ GAMEOBJECT_DESC
→ Add_GameObject_ToLayer
→ Runtime Clone

B01에서 확인한 기존 Spawn Path를 Save / Load에서도 다시 사용한다는 점이 핵심입니다.

Load = Pointer 복원

이 아닙니다.

Load = 저장된 Identity / State를 이용해 기존 Runtime Path를 다시 실행

입니다.

DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2B_ApplyLoadedTransform.png

Source 1F — Apply Loaded Transform

파일: DX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2B_ApplyLoadedTransform.png

새로 구성된 Runtime Object에 저장된 Transform을 적용하는 마지막 경계입니다.

Text
Saved Rotation(deg)
→ DegreesToRadians
→ Runtime Rotation(rad)
 
Position / Scale / Rotation
→ ApplyLoadedObjectTransform
→ Runtime Transform

이 장까지 연결해야 Scene Object Load가 단순 Parse가 아니라 Runtime Reconstruction + Transform Restore까지 이어졌다고 설명할 수 있습니다.

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

Runtime Pointer를 저장하지 않고, 다시 구성 가능한 Identity와 Transform State를 저장한 뒤 기존 Runtime Spawn Path로 Object를 다시 만들고 Transform을 적용합니다.

Source는 책임 흐름을 보여주고, 실제 Roundtrip 결과는 앞의 Video 1이 담당합니다.


Source Flow와 Runtime State의 역할을 구분합니다

공개 본문은 Source + Roundtrip Video를 중심으로 유지합니다.

현재 B03 공개 Evidence에는 별도의 Debugger / Watch Screenshot을 포함하지 않습니다. 따라서 아래 내용은 “이미 공개 Screenshot으로 증명했다”는 의미가 아니라, Persistence 문제를 실제로 디버깅할 때 확인할 Runtime State 경계입니다.

Scene Object Persistence를 확인할 때는 다음 세 지점에서 State가 어떻게 이동하는지 비교합니다.

경계확인할 값
Save 직전 RuntimePosition / Scale / Rotation(rad)
Serialize / Parse 이후Position / Scale / Rotation(deg)
Load Apply 이후 RuntimePosition / Scale / Rotation(rad)

특히 Rotation은 rad → deg → deg → rad 경계를 지나기 때문에, 이 값들이 기대한 의미로 이어지는지 확인하면 Rotation만 틀어지는 문제의 범위를 빠르게 줄일 수 있습니다.

Debugger Capture를 남길 때도 Watch를 많이 펼쳐놓지 않습니다. 실제 Current Source에 존재하는 변수명으로, Claim에 필요한 값 2~4개만 확인합니다.

예를 들면 다음 세 시점이 유용합니다.

  1. Save 직전 — Runtime Transform에서 실제 Rotation을 읽는 지점
  2. Parse 직후 — LoadObjectStates가 Degree 값을 GameObjectState로 만든 지점
  3. Apply 직전 / 직후 — ApplyLoadedObjectTransform이 Runtime Transform에 값을 적용하는 지점

Debugger를 사용할 때의 목적은 “Debugger를 썼다”는 사실을 보여주는 것이 아니라:

Save / Parse / Apply 중 어느 경계에서 State의 의미가 달라졌는지 확인하는 것

입니다.

Watch 값을 Evidence로 사용할 경우에는 실제 Runtime Capture에서 확인된 값만 사용하고, 블로그를 위해 임의 숫자를 만들지 않습니다.


전체 Scene을 자동 Snapshot하는 구조는 아닙니다

Scene Object Save의 범위도 명확하게 잡았습니다.

현재 Scene 전체를 자동으로 직렬화하는 범용 Scene Snapshot System이 아니라, Tool이 선택하고 관리하는 Runtime Object State를 기준으로 저장합니다.

Text
m_PickedObjects
→ Live Runtime Object인지 확인
→ 다시 구성 가능한 State 수집
→ Save

Picked Pointer가 존재한다고 해서 현재 Object가 반드시 살아 있다고 볼 수는 없습니다.

그래서 저장 전에 실제 Live Layer에 존재하는 Object인지 확인하고 stale entry를 정리하는 방어도 넣었습니다.


UI Layout Editor

UI는 이미 존재하는 Runtime Object가 State를 소유합니다

UI Layout Tool은 Scene Object Tool과 구조가 다릅니다.

Scene Object는 Load할 때 Runtime Clone을 다시 만들지만, MapCard와 BACK 같은 UI는 이미 Runtime에 존재합니다.

따라서 별도의 Editor UI Transform을 하나 더 만들지 않았습니다.

역할Owner
State OwnerRuntime UI (X / Y / SizeX / SizeY)
WriterEditor
ReaderRender
ReaderHit Test

Tool에서 UI를 움직이면 그 값이 바로 실제 Render와 Hit Test에 사용됩니다.


Direct Drag도 실제 Runtime Layout State를 수정합니다

UI Editor의 큰 흐름은 다음과 같습니다.

Text
Edit Mode ON
→ Mouse Position
→ UI Hit Test
→ Stable UI Identity 선택
→ Drag Start
→ Mouse / UI Offset 저장
→ Drag
→ X / Y 변경
→ Render / Hit Test 즉시 반영

Drag를 시작했을 때 UI Center를 Mouse 위치로 강제로 붙이지 않고 처음 잡은 Offset을 유지합니다.

Drag Offset = Mouse Click Position - UI Origin / Center

이렇게 해야 UI가 클릭 순간 Mouse 중앙으로 튀는 현상을 피할 수 있습니다.

Position Drag와 Size Edit도 역할을 나눴습니다.

  • Drag → Position
  • Resize → SizeX / SizeY

화면 위치와 Click 영역도 같은 State를 읽어야 합니다

UI가 화면에서는 이동했는데 Click 영역은 원래 자리에 남아 있다면 Runtime State가 두 벌로 갈린 것입니다.

그래서 Render용 Layout State와 Hit Test용 Layout State를 별도로 유지하지 않았습니다.

둘 다 같은 Runtime UI의 X / Y / SizeX / SizeY를 읽습니다.

특히 BACK처럼 실제 Interaction이 있는 UI는 Visual 이동 + Hit Area 이동 + Click 동작이 함께 맞아야 합니다.


Edit Mode의 Click과 실제 Gameplay Click도 분리했습니다

Editor에서 MapCard나 BACK을 옮기려고 Click했는데 실제 Map Selection이나 BACK 동작까지 실행되면 Authoring이 어렵습니다.

그래서 역할을 분리했습니다.

ModeMouse Click의 의미
Edit Mode ONEditor Select / Drag, Gameplay Click Side Effect 억제
Edit Mode OFF원래 Gameplay UI Input

같은 Mouse Click을 사용하더라도 Authoring Input과 Gameplay Input의 책임을 분리했습니다.


UI Layout도 Pointer가 아니라 Stable Identity를 저장합니다

UI Layout Persistence 역시 Pointer Address를 저장하지 않습니다.

Text
# UiLayout v1
PrototypeTag X Y SizeX SizeY

저장 기준은 Stable UI Identity + X / Y + SizeX / SizeY입니다.

Current Screen Position이나 Array Index, Pointer Address처럼 Runtime을 다시 시작하거나 Layout이 바뀌면 의미가 달라질 수 있는 값은 Identity로 사용하지 않았습니다.


UI Layout Load는 새 UI를 Spawn하지 않습니다

UI Layout Load는 다음처럼 이어집니다.

Text
UiLayout.txt
→ Stable ID Parse
→ Existing Runtime UI Lookup
→ Set_LayoutRect
→ Existing Runtime UI State Update

이미 존재하는 MapCard / BACK을 Stable Identity로 찾고 State만 갱신합니다.

과거 File에 지금은 없는 ID가 남아 있다면 전체 Load를 실패시키기보다 해당 ID를 건너뜁니다.

Unknown ID → Skip

즉 UI Layout Load는 새 UI를 Spawn하는 과정이 아니라 Existing Runtime UI State Update입니다.


🎥 Video 2. Runtime UI를 직접 편집하고 Save → Load로 Layout을 복원

파일: DX11-B03_Video_02_UILayout_SaveLoad_Roundtrip.mkv

MapCard 또는 BACK 선택 → Drag → Resize → Save → 일부러 위치를 다시 변경 → Load → 저장된 Layout 복원까지 보여줍니다.

이 영상에서는 단순히 UI가 움직이는 것보다 다음 흐름이 한 번에 읽히는 것이 중요합니다.

Text
Tool Input
→ Existing Runtime UI State Change
→ Save
→ Change
→ Load
→ Existing UI Restore

🔡 Source 2A~2D. UI Layout Persistence — Runtime State Owner → Parse → Stable Lookup → Existing UI Apply

UI Layout은 Scene Object와 달리 Load할 때 새 Instance를 만들지 않습니다.

이 흐름은 Runtime State Owner → Parse Record → Stable Identity Lookup → Existing UI Apply의 네 단계로 나눠 읽습니다.

DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load0_MapCard_RuntimeState.png

Source 2A — MapCard Runtime State

파일: DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load0_MapCard_RuntimeState.png

실제 Runtime UI가 Layout 값을 소유한다는 시작점입니다.

Text
Runtime UI
→ X / Y / SizeX / SizeY

Editor 전용 Layout State를 따로 두는 것이 아니라, 실제 Render / Hit Test가 읽는 Runtime UI State를 Tool이 수정합니다.

이 장의 핵심 질문:

“실제로 화면에 그려지는 UI의 위치와 크기를 누가 소유하는가?”

DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load1_UiLayout_ParseRecord.png

Source 2B — UiLayout Parse Record

파일: DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load1_UiLayout_ParseRecord.png

UiLayout.txt의 Stable Identity와 Layout 값을 Runtime에서 사용할 Record로 읽는 경계입니다.

Text
UiLayout.txt
→ Stable Identity
+ X / Y / SizeX / SizeY
→ Parsed Layout Record
DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load2_StableIdentity_ExistingLookup.png

Source 2C — Stable Identity → Existing UI Lookup

파일: DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load2_StableIdentity_ExistingLookup.png

Parse된 Stable Identity로 이미 존재하는 Runtime UI Object를 찾는 단계입니다.

Text
Stable UI Identity
→ Existing Runtime UI Lookup

Pointer Address나 Screen Position을 Identity로 쓰지 않는 이유가 여기서 드러납니다.

DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load3_ApplyExistingUI.png

Source 2D — Apply Existing UI

파일: DX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load3_ApplyExistingUI.png

찾은 Runtime UI에 저장된 Layout State를 적용하는 마지막 경계입니다.

Text
Existing Runtime UI
→ Set_LayoutRect
→ X / Y / SizeX / SizeY Update
→ Render / Hit Test에서 같은 State 사용

즉 UI Load의 의미는:

Text
새 UI Spawn
X
 
Existing UI State Update
O

입니다.

DX11-B03_Backup_Source_UILayout_SetLayoutRect_Dispatch.png

🔎 Deep Dive Source — SetLayoutRect Dispatch

파일: DX11-B03_Backup_Source_UILayout_SetLayoutRect_Dispatch.png

이 Source는 UI Layout 적용이 실제 Runtime UI의 Layout Setter / Dispatch 경계로 넘어가는 지점을 더 깊게 확인할 때 사용합니다.

본문의 Source 2A~2D만으로 기본 흐름은 충분하고, 이 화면은 면접에서 Apply 경계를 더 자세히 물을 때 연결하는 Deep Dive 자료입니다.

다만 질문이 다음처럼 들어오면 바로 연결할 수 있습니다.

Text
"Parsed Layout 값이 실제 Runtime UI에 어디서 적용되나요?"

그때:

Text
Stable Identity Lookup
→ Existing UI
→ SetLayoutRect Dispatch
→ Runtime Layout State Update

로 설명합니다.


UI Layout은 Autosave하지 않습니다

Editor에서 값을 바꾸면 Runtime에는 즉시 반영됩니다.

하지만 Disk Write까지 자동으로 확정하지는 않았습니다.

단계의미
EditRuntime Live Preview
Explicit SaveDisk Write

즉 지금 화면에서 시험 중인 값과 저장된 Authoring Data를 구분했습니다.

잘못 Drag한 순간 파일까지 덮어쓰지 않고, 사용자가 Save를 눌렀을 때만 UiLayout.txt를 갱신합니다.


Scene Object와 UI Layout은 같은 Save / Load가 아닙니다

둘을 비교하면 차이가 더 명확합니다.

항목Scene Object ToolUI Layout Editor
대상Runtime GameObjectExisting Runtime UI
IdentityPrototype / Type + LayerStable UI Identity
StatePosition / Scale / RotationX / Y / SizeX / SizeY
FileObjectsSaved.txtUiLayout.txt
LoadState Parse → Runtime SpawnStable ID Lookup
결과Runtime Clone ReconstructionExisting UI State Update
Load 시 새 InstanceOX
Editor-only State없음없음

한 줄로 줄이면:

Scene Object Load = Reconstruction

UI Layout Load = Existing State Update

Save / Load라는 이름이 같아도 대상의 Lifetime과 State Owner가 다르면 구현 방식도 달라져야 했습니다.


문제가 생기면 State가 이동하는 경계를 따라 확인합니다

Scene Object가 Spawn되지 않으면:

Text
Prototype
→ Layer
→ Picking
→ Add_GameObject_ToLayer
→ Clone
→ Component
→ Layer Insert

Save가 이상하면 Picked Object valid? → State collected? → File written? 순서로 보고, Load가 이상하면 File parsed? → State vector? → CMainApp Spawn Loop? → Add_GameObject_ToLayer? → Transform Apply? 순서로 확인합니다.

Rotation만 다르면:

Text
Runtime Radian
→ Saved Degree
→ Parsed Degree
→ Runtime Radian

경계를 따라 실제 값이 언제 달라지는지 확인합니다.

UI 쪽도 마찬가지입니다. Visual과 Click 위치가 다르다면 Render가 읽는 Layout State와 Hit Test가 읽는 Layout State가 같은지부터 확인합니다.

마지막 화면 결과만 보는 대신 State가 이동하는 경계 중 어디에서 처음 값이 달라졌는지를 먼저 봅니다.


이 Tool을 상용 Editor처럼 설명하지 않습니다

이 프로젝트에서 실제로 설명할 수 있는 범위는 다음입니다.

  • Runtime Object Tool이 실제 Gameplay Spawn Path를 사용합니다.
  • 실제 Runtime Transform을 직접 수정합니다.
  • Position / Scale / Rotation을 저장합니다.
  • Rotation 단위를 Save / Load에서 변환합니다.
  • Old Row의 Rotation 누락을 처리합니다.
  • Scene Load는 Runtime Clone Reconstruction입니다.
  • UI Layout Editor가 실제 Runtime UI State를 수정합니다.
  • UI Layout Load는 Existing UI State Update입니다.
  • Direct Drag에서 Offset을 유지합니다.
  • Edit Mode와 Gameplay Input을 분리합니다.

반대로 다음과 같이 과장하지 않습니다.

  • Commercial Editor
  • 전체 Scene 자동 Snapshot
  • Pointer를 Disk에 저장
  • UI Load가 새 UI를 Spawn
  • Autosave
  • 범용 Editor Framework

제가 만든 것은 이 프로젝트에서 실제로 필요했던 Runtime Authoring / Persistence Tool입니다.


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

B03의 Evidence는 역할 기준으로 네 묶음입니다.

Text
Scene Runtime Roundtrip
Scene Persistence Source
UI Runtime Roundtrip
UI Persistence Source

실제 파일은 Source를 읽기 좋은 단계로 나누고 Deep Dive Source를 포함해 총 13개입니다.

Scene Object — 7개

역할실제 파일이 자료가 닫는 질문
Runtime RoundtripDX11-B03_Video_01_MapTool_SaveLoad_Restore.mkv실제 Object를 Edit → Save → Reload → Restore할 수 있는가?
Save SchemaDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0A_SaveObjectStates_Schema.png무엇을 저장해야 Runtime Object를 다시 구성할 수 있는가?
Save WriteDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow0B_SaveObjectStates_Write.pngRuntime State가 실제 File Write로 어떻게 넘어가는가?
Load ParseDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1A_LoadObjectStates_Parse.pngFile Row가 어떻게 GameObjectState로 해석되는가?
Rotation CompatibilityDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow1B_LoadObjectStates_RotationCompatibility.png예전 Row에 Rotation이 없을 때 어떻게 처리하는가?
Runtime ReconstructionDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2A_RuntimeReconstruction.pngParsed State가 어떻게 기존 Spawn Path로 돌아가는가?
Transform ApplyDX11-B03_Screenshot_01_Source_ObjectPersistence_Flow2B_ApplyLoadedTransform.png저장된 Transform을 새 Runtime Instance에 어떻게 적용하는가?

UI Layout — 6개

역할실제 파일이 자료가 닫는 질문
Runtime RoundtripDX11-B03_Video_02_UILayout_SaveLoad_Roundtrip.mkvUI Drag / Resize / Save / Change / Load / Restore가 실제로 이어지는가?
Runtime State OwnerDX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load0_MapCard_RuntimeState.pngLayout State를 실제로 누가 소유하는가?
Parse RecordDX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load1_UiLayout_ParseRecord.pngFile State를 어떻게 Runtime Record로 읽는가?
Stable LookupDX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load2_StableIdentity_ExistingLookup.png저장된 ID로 어떤 Runtime UI를 찾는가?
Apply Existing UIDX11-B03_Screenshot_02_Source_UILayout_StateOwner_Load3_ApplyExistingUI.png기존 UI에 Layout State를 어떻게 적용하는가?
Deep Dive DispatchDX11-B03_Backup_Source_UILayout_SetLayoutRect_Dispatch.pngSetLayoutRect 적용 경계를 더 깊게 어디서 확인할 수 있는가?

가장 쉬운 읽기 순서

Text
① Scene Video
실제 Save / Reload 결과를 먼저 본다
 
→ ②~⑦ Scene Source
Save → Parse → Reconstruction → Apply를 따라간다
 
→ ⑧ UI Video
실제 Layout Roundtrip을 본다
 
→ ⑨~⑫ UI Source
State Owner → Parse → Stable Lookup → Apply를 따라간다
 
→ ⑬ Backup SetLayoutRect Dispatch
더 깊은 질문이 있을 때만 본다

모든 Source Screenshot을 같은 밀도로 읽을 필요는 없습니다.

먼저 이해해야 할 것은:

Text
Scene Object Load
= Runtime Reconstruction
 
UI Layout Load
= Existing State Update

라는 차이입니다.

그 다음 더 깊이 보고 싶은 경우에만 세부 Source를 따라가도록 배치합니다.


게임 클라이언트 관점에서 이 흐름이 중요한 이유

Persistence 문제는 “파일이 저장됐는가?”만 보면 원인을 놓치기 쉽습니다.

B03에서는 State가 이동하는 경계를 나눠서 봅니다.

Text
Scene Object가 복원되지 않음
→ Parse
→ Runtime Reconstruction
→ Transform Apply
 
Rotation만 이상함
→ radian / degree 변환 경계
 
UI가 보이는 위치와 Click 위치가 다름
→ Render와 Hit Test가 같은 Layout State를 읽는지 확인
 
UI Load가 안 됨
→ Stable Identity Parse
→ Existing UI Lookup
→ Set_LayoutRect Apply

즉 Tooling의 핵심은 UI 기능의 개수가 아니라, State Owner와 Persistence Boundary를 분리해서 문제를 좁힐 수 있다는 점입니다.


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

“Runtime Tool에서는 Editor 전용 Object나 Layout State를 따로 만들지 않고 실제 Runtime State를 수정했습니다. Scene Object는 Prototype / Layer Identity와 Position / Scale / Rotation을 저장하고, Load할 때 기존 Add_GameObject_ToLayer 경로로 Runtime Instance를 다시 구성한 뒤 Transform을 적용합니다. 반면 UI Layout은 이미 존재하는 Runtime UI를 Stable Identity로 찾아 X / Y / SizeX / SizeY만 갱신합니다. 그래서 둘 다 Save / Load지만 Scene은 Reconstruction이고 UI는 Existing State Update입니다.”

이 답변에서 가장 중요한 구분은:

Text
Pointer 저장
X
 
Identity + State 저장
O

그리고:

Text
Scene Load
→ New Runtime Instance Reconstruction
 
UI Load
→ Existing Runtime Instance Update

입니다.


정리

DX11-SpongeBob-BFBB의 Runtime Tooling을 가장 짧게 줄이면 다음과 같습니다.

Text
Tool Input
→ Real Runtime State
→ Player-visible Result
→ Serialize
→ File
→ Load
→ Runtime Apply
→ Player-visible Result

그리고 Scene Object와 UI Layout의 Load는 서로 다릅니다.

대상Load 결과
Scene ObjectRuntime Clone Reconstruction
UI LayoutExisting Runtime UI State Update

제가 이 구조에서 가져간 핵심은 ImGui 기능을 많이 만들었다는 것이 아니라, 누가 실제 Runtime State를 소유하는지, 무엇을 저장해야 다시 구성할 수 있는지, Load 후 어떤 Runtime 책임으로 돌아가야 하는지를 구분해서 구현하고 디버깅한 경험입니다.

또한 Source Flow만 보는 데서 끝내지 않고, 문제가 생기면 Save 직전 / Parse 이후 / Apply 이후의 Runtime State를 Breakpoint와 Watch로 비교해 어느 경계에서 값의 의미가 달라졌는지 좁히는 방식으로 확인합니다.

다음 B04에서는 이 Map Runtime 위에서 목적지 Map은 정상적으로 바뀌었는데 Player / Camera / Navigation Restore가 어긋났던 문제를, 앞 단계부터 정상 영역을 닫아가며 원인을 좁힌 Debug Story로 정리합니다.

빠른 검색

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

목차