MFC-B02 | MFC-Crazy-Arcade — Tool에서 배치한 타일이 데이터와 Client 화면으로 이어지는 흐름
이 글에서 확인할 내용
MFC-Crazy-Arcade에서 제가 맡았던 타일 배치 작업은 Tool 화면 안에서 끝나는 기능이 아니었습니다.
Tool에서 선택한 타일 값이 CToolView의 마우스 입력을 거쳐 CTerrain의 TILE 데이터에 반영되고, 프로젝트의 저장 흐름을 통해 Map Data로 남은 뒤 Client의 CMyTerrain에서 다시 읽혀 화면에 사용되는 구조였습니다.
당시에는 이 과정을 지금처럼 명확하게 설명하지 못했습니다.
그냥 “맵툴에서 타일을 배치했다” 정도로 생각했습니다.
하지만 프로젝트 코드를 다시 따라가 보니, 타일 배치는 하나의 화면이나 하나의 함수에서 끝나는 작업이 아니었습니다.
Text
Tool에서 타일 선택
↓
마우스 입력으로 배치
↓
TILE 데이터 변경
↓
Map Data 저장
↓
Client에서 Load
↓
Terrain Render이 글에서는 제가 직접 맡았던 타일 배치 경험을 중심으로, Tool에서 만든 결과가 데이터로 남고 Client Runtime에서 다시 사용되는 전체 흐름을 정리합니다.
프로젝트 전체 Tool / Save / Client 구조를 제가 혼자 구현했다는 의미는 아닙니다.
제가 맡은 타일 배치 영역과 연결된 프로젝트 코드를 다시 따라가며 확인한 흐름까지 구분해서 설명합니다.
전체 흐름을 먼저 보면
타일 하나가 Tool에서 선택되어 실제 Client 화면에 다시 보이기까지의 과정은 크게 세 구간으로 나눌 수 있습니다.
Text
1. Tool 편집
타일을 선택하고 원하는 위치에 배치
2. Map Data 저장
변경된 TILE 데이터를 파일로 저장
3. Client Runtime
저장된 데이터를 읽어 Terrain으로 표시프로젝트의 Class 흐름으로 조금 더 자세히 보면 다음과 같습니다.
Text
CMyForm
↓
CMapTool
↓
CToolView
↓
CTerrain
↓
TILE Data
↓
Map .dat
↓
CMyTerrain
↓
Client Terrain Render처음에는 이 Class들이 한 덩어리처럼 보였습니다.
다시 따라가 보니 역할은 비교적 분명했습니다.
Text
Tool
→ 데이터를 선택하고 수정
Map Data
→ 편집 결과를 저장
Client
→ 저장된 데이터를 읽고 실제 게임 화면에 사용제가 이 프로젝트에서 가장 중요하게 보는 것도 이 구분입니다.
Tool에서는 누가 무엇을 담당했는가
CMyForm — Tool의 진입점
CMyForm은 직접 타일을 칠하는 Class라기보다 여러 Tool 기능으로 들어가는 패널에 가까웠습니다.
프로젝트에는 CMapTool, CUnitTool, CPathFind 같은 Dialog가 있었고, CMyForm에서 각 기능으로 진입하는 구조였습니다.
Text
CMyForm
→ Tool Hub
CMapTool
→ 타일 선택 / Map 관련 기능
CUnitTool
→ Unit 관련 기능
CPathFind
→ Path 관련 기능타일 편집 자체의 중심은 이후 CMapTool → CToolView → CTerrain 흐름에 있었습니다.
CMapTool — 현재 사용할 타일 선택
Tool에서 타일을 배치하려면 먼저 “어떤 타일을 사용할 것인가”가 필요합니다.
CMapTool에서는 현재 선택된 Tile ID를 관리합니다.
Tile ID는 쉽게 말하면 어떤 타일 이미지를 사용할지 구분하는 번호입니다.
Text
MapTool에서 타일 선택
↓
현재 Tile ID 변경
↓
이후 마우스 입력에서 선택 값 사용처음에는 “MapTool에서 타일을 찍는다”고 생각하기 쉬웠습니다.
하지만 다시 보면 CMapTool은 선택 값을 제공하고, 실제 위치 입력과 Terrain 데이터 변경은 다른 Class가 담당했습니다.
CToolView — 마우스 입력과 편집 화면
CToolView는 실제 맵을 편집하는 main canvas 역할을 합니다.
사용자가 맵 위에서 마우스를 클릭하거나 드래그하면 현재 선택된 Tile ID를 읽고, 해당 위치의 Terrain 데이터를 바꾸는 흐름으로 이어집니다.
Text
CMapTool에서 Tile ID 선택
↓
CToolView에서 마우스 입력
↓
현재 Tile ID 확인
↓
CTerrain::Tile_Change이 구조를 다시 보면서 UI에서 값을 선택하는 것과, 실제 데이터를 수정하는 입력 처리가 분리되어 있다는 점을 이해할 수 있었습니다.
CTerrain — 실제 TILE 데이터
실제 타일 데이터는 CTerrain 쪽에서 관리됩니다.
CTerrain은 TILE 데이터를 보유하고 있고, Tile_Change를 통해 선택된 위치의 값을 변경합니다.
Text
CToolView
↓
CTerrain::Tile_Change
↓
선택 위치의 TILE 데이터 변경즉 Tool 화면에서 보이는 결과의 기준은 결국 CTerrain이 가지고 있는 실제 타일 데이터였습니다.
TILE 데이터가 Tool과 Client를 이어주는 부분
이 흐름에서 가장 중요한 데이터는 TILE입니다.
TILE은 복잡한 Gameplay Class라기보다, 한 칸의 타일 정보를 담고 있는 데이터 구조에 가깝습니다.
프로젝트에서 확인한 주요 값은 다음과 같습니다.
Text
byDrawID
→ 어떤 타일 이미지를 그릴지 결정
byOption
→ 이동 가능 / 장애물 같은 타일 옵션에 사용될 수 있는 값
vPos
→ 타일 위치
vSize
→ 타일 크기이 가운데 타일 배치 흐름에서 가장 직접적으로 연결되는 값은 byDrawID였습니다.
Text
Tool에서 선택한 Tile ID
↓
TILE::byDrawID
↓
Client에서 어떤 Tile Texture를 사용할지 결정겉으로 보면 단순한 숫자 하나지만, 이 값이 Tool에서 선택한 결과와 Client에서 보이는 타일을 이어주는 기준이었습니다.
이 경험 이후 화면 결과만 보는 것이 아니라, 그 결과를 결정하는 데이터가 무엇인지 같이 확인하려고 하게 됐습니다.
main view와 minimap은 같은 Terrain 데이터를 봅니다
Tool에는 main view뿐 아니라 minimap도 있었습니다.
처음에는 두 화면이 각각 별도의 맵 데이터를 가지고 있다고 생각할 수도 있습니다.
하지만 프로젝트 구조를 다시 보면 CMiniView가 독립적인 맵 데이터를 따로 가지는 방식이 아니라, CToolView가 가진 같은 CTerrain 데이터를 기준으로 Mini_Render를 호출해 축소해서 보여주는 흐름이었습니다.
Text
CToolView
└─ CTerrain
├─ Render
│ → main view
│
└─ Mini_Render
→ minimap즉 main view에서 바꾼 타일이 minimap에도 반영되는 이유는, 서로 다른 맵을 동기화하는 것이 아니라 같은 Terrain 데이터를 서로 다른 방식으로 그리기 때문이었습니다.
이 부분도 당시에는 단순히 “미니맵에도 보인다” 정도로 생각했지만, 다시 보면 데이터 소유와 화면 표현을 나누어 이해하는 데 도움이 됐습니다.
Tool에서 만든 결과를 Map Data로 남기는 과정
Tool에서 타일을 배치해도 실행 중에만 값이 남아 있다면 Client에서 다시 사용할 수 없습니다.
프로젝트에는 CTerrain이 가지고 있는 타일 데이터를 .dat 파일로 저장하는 흐름이 있었습니다.
Text
CTerrain
→ TILE 데이터 보유
CMapTool::OnSaveData
→ Terrain의 Tile Data 접근
Map .dat
→ 배치 결과 저장프로젝트 코드를 다시 보면 CMapTool이 Tile Data를 직접 소유하는 구조는 아니었습니다.
실제 데이터는 CTerrain 쪽에 있고, 저장 시점에 CMapTool이 CMainFrame과 CToolView를 거쳐 Terrain 데이터에 접근하는 흐름이었습니다.
Text
CMapTool
↓
CMainFrame
↓
CToolView
↓
CTerrain
↓
Tile Vector지금 기준에서 보면 Class 사이의 접근 경로가 길고 결합도가 높은 구조로 보입니다.
하지만 당시 학습 단계에서는 이 구조를 통해 중요한 경험을 할 수 있었습니다.
Text
화면에서 편집한 결과
!= 실행 중에만 존재하는 임시 값
화면에서 편집한 결과
→ 파일로 저장
→ Client에서 다시 사용제가 이 프로젝트에서 Save 흐름을 의미 있게 보는 이유도 이 지점입니다.
Client에서는 저장된 Map Data를 다시 읽습니다
Client는 MFC Tool 화면이나 Dialog를 사용하는 프로그램이 아닙니다.
Tool에서 만들어진 Map Data를 읽고 실제 게임 화면을 구성합니다.
Client 쪽에서는 CMyTerrain이 이 역할의 중심에 있었습니다.
프로젝트 흐름을 따라가면 다음과 같이 이어집니다.
Text
CStage::Ready_Scene
↓
CMyTerrain 생성
↓
CMyTerrain::Initialize
↓
Load_Tile
↓
Map2.dat 읽기
↓
TILE 데이터 구성
↓
CObjMgr의 TERRAIN Layer에 등록Tool에서 편집한 TILE 데이터가 파일에 저장되고, Client에서 다시 같은 형태의 데이터로 읽혀 Terrain을 구성하는 방식입니다.
제가 처음으로 Tool에서 만드는 데이터와 Runtime에서 사용하는 데이터가 실제로 이어지는 지점을 본 부분이기도 합니다.
Client에서는 byDrawID로 타일 Texture를 선택합니다
Map Data를 읽었다고 바로 화면에 타일이 보이는 것은 아닙니다.
Client는 각 TILE의 byDrawID를 확인하고, 그 번호에 해당하는 Texture를 찾아 화면에 그립니다.
프로젝트의 Render 흐름은 다음과 같습니다.
Text
CMyTerrain::Render
↓
현재 TILE의 byDrawID 확인
↓
CTextureMgr::Get_Texture(
"Terrain",
"Tile",
byDrawID
)
↓
해당 Texture 선택
↓
Sprite Draw즉 Tool에서 선택한 Tile ID가 최종적으로 다음 흐름으로 이어집니다.
Text
Tool의 Tile ID
↓
TILE::byDrawID
↓
Map Data 저장
↓
Client Load
↓
Terrain / Tile Texture의 Frame Index
↓
화면 결과이 흐름을 따라가면서 “타일을 배치했다”는 말 뒤에 실제로 어떤 데이터 연결이 있는지 더 구체적으로 이해하게 됐습니다.
Map Data만 맞는다고 화면이 나오는 것은 아닙니다
Client에서 정상적으로 타일을 그리려면 Map Data뿐 아니라 Texture도 준비되어 있어야 합니다.
Client는 byDrawID를 기준으로 Texture를 찾기 때문에, 해당 번호로 찾을 수 있는 Texture가 미리 등록되어 있어야 합니다.
프로젝트에서는 Client 시작 과정에서 Texture 정보를 읽어 등록하는 흐름이 있었습니다.
Text
CStage::Ready_Scene
↓
CTextureMgr::ReadImgPath
↓
ImgPath.txt
↓
ObjKey / StateKey / Count / Path 읽기
↓
CTextureMgr::Insert_Texture
↓
CMultiTexture에 Frame Texture 등록Terrain 타일 기준으로 보면 다음 세 값이 서로 맞아야 합니다.
Text
ObjKey
→ Terrain
StateKey
→ Tile
FrameIndex
→ TILE::byDrawID그래서 실제 화면 결과에는 두 종류의 데이터가 함께 맞아야 했습니다.
Text
Map Data
→ 어떤 Tile ID를 사용할 것인가
Texture Data
→ 그 Tile ID에 해당하는 이미지가 준비되어 있는가둘 중 하나만 맞지 않아도 기대한 타일이 정상적으로 보이지 않을 수 있습니다.
이 부분을 다시 따라가면서 Map Data와 Texture 등록이 서로 완전히 별개의 문제가 아니라, Render 시점에서 하나의 결과로 만나는 정보라는 것을 이해하게 됐습니다.
Tool과 Client의 Texture는 같은 Registry가 아닙니다
이 프로젝트를 다시 볼 때 헷갈리기 쉬웠던 부분도 있었습니다.
Tool과 Client가 같은 CTextureMgr 인스턴스를 공유하는 구조는 아니었습니다.
각 프로그램 안에서 필요한 Texture를 각각 준비했습니다.
Tool 쪽은 편집 화면에서 타일을 보여주기 위해 CTerrain::Initialize에서 Insert_Texture를 사용하는 방식이 중심이었고, Client는 ImgPath.txt를 읽는 방식으로 Runtime Texture를 준비했습니다.
Text
Tool
CTerrain::Initialize
↓
필요한 Tile Texture 등록
↓
편집 화면에서 사용Text
Client
ImgPath.txt
↓
CTextureMgr::ReadImgPath
↓
Runtime Texture 등록
↓
CMyTerrain::Render에서 사용즉 두 프로그램은 같은 Map Data 흐름으로 연결되지만, Texture Registry 자체를 공유하는 것은 아니었습니다.
이 차이는 이후 프로젝트에서도 Editor와 Runtime을 구분해서 보는 데 도움이 됐습니다.
겉으로 같은 Asset을 보여주더라도, Editor와 Runtime에서 실제로 데이터를 준비하고 소유하는 경로는 다를 수 있다는 점을 알게 됐습니다.
이 흐름을 다시 보면서 정리한 기준
프로젝트 코드를 다시 따라가면서 몇 가지를 명확하게 구분할 수 있었습니다.
첫 번째는 CMapTool의 역할입니다.
CMapTool이 전체 Tile Data를 직접 소유한다기보다, 현재 선택된 Tile ID를 관리하고 저장 흐름에 관여하는 쪽에 가깝습니다.
실제 타일 데이터는 CTerrain이 가지고 있습니다.
두 번째는 CToolView의 역할입니다.
CToolView는 선택 값을 직접 소유하기보다, 마우스 입력을 받아 현재 선택된 값을 Terrain 변경으로 연결하는 편집 화면입니다.
세 번째는 CMiniView입니다.
CMiniView가 별도의 맵 데이터를 유지하는 것이 아니라, main view와 같은 CTerrain 데이터를 축소해서 보여줍니다.
네 번째는 Tool과 Client입니다.
Text
Tool
→ 데이터를 만든다
Client
→ 저장된 데이터를 사용한다같은 맵을 다루지만 프로그램 안의 Texture 준비 방식과 Runtime 흐름은 서로 달랐습니다.
이 구분을 하고 나니 전체 구조를 훨씬 이해하기 쉬웠습니다.
제가 이 프로젝트에서 가져간 기준
이 프로젝트에서 가장 크게 남은 것은 특정 Class 이름이 아닙니다.
처음으로 다음 연결을 직접 따라가 봤다는 점입니다.
Text
사용자 입력
↓
편집 데이터
↓
저장 데이터
↓
Runtime Load
↓
Render 결과이전에는 화면에 원하는 결과가 나오면 기능이 끝났다고 생각하기 쉬웠습니다.
MFC-Crazy-Arcade 이후에는 화면 뒤에 있는 데이터를 같이 보게 됐습니다.
Text
어떤 값이 화면 결과를 결정하는가?
그 값은 누가 가지고 있는가?
언제 저장되는가?
Runtime에서는 누가 다시 읽는가?이 질문은 이후 DirectX11과 Unreal 프로젝트에서도 계속 이어졌습니다.
Runtime
당시 프로젝트의 실제 동작 결과는 아래 영상에서 확인할 수 있습니다.
이 영상은 현재 대표 프로젝트의 기술 깊이를 보여주기 위한 자료라기보다, Tool 기반 타일 배치와 팀 프로젝트 결과물이 실제 게임 화면으로 이어졌던 당시 작업을 확인할 수 있는 기록입니다.
이후 프로젝트로 이어진 부분
MFC-Crazy-Arcade에서 경험한 흐름은 이후 DX11-SpongeBob-BFBB의 Editor 작업을 이해할 때 다시 연결됐습니다.
DX11 프로젝트에서는 ImGui Editor에서 오브젝트를 선택하고 배치한 뒤 ObjectsSaved.txt에 저장하고, 다시 Runtime에서 불러오는 흐름을 다뤘습니다.
Text
MFC-Crazy-Arcade
Tile 선택
→ TILE Data
→ Map Data
→ Client TerrainText
DX11-SpongeBob-BFBB
Object 선택
→ 배치
→ ObjectsSaved
→ Load
→ Runtime 배치 검증대상은 타일에서 3D Object로 달라졌지만, Editor에서 만든 결과를 데이터로 남기고 Runtime에서 다시 사용하는 흐름이라는 점에서는 이어지는 부분이 있었습니다.
Unreal 프로젝트에서도 Editor에서 설정한 DataAsset이나 Gameplay 설정이 실제 Runtime에서 언제 로드되고 누구에게 사용되는지 확인하려는 기준으로 이어졌습니다.
정리
MFC-Crazy-Arcade에서 타일 배치를 맡으면서 처음에는 화면에 타일을 놓는 작업이라고 생각했습니다.
하지만 프로젝트 구조를 다시 따라가 보니 실제 흐름은 훨씬 길었습니다.
Text
CMapTool에서 타일 선택
↓
CToolView에서 입력 처리
↓
CTerrain의 TILE 데이터 변경
↓
Map Data 저장
↓
Client의 CMyTerrain에서 Load
↓
TILE::byDrawID로 Texture 선택
↓
Terrain Rendermain view와 minimap은 같은 Terrain 데이터를 서로 다른 방식으로 보여주고 있었고, Tool과 Client는 같은 Map Data 흐름에 연결되면서도 각각 별도의 Texture 준비 과정을 가지고 있었습니다.
이 경험을 통해 처음으로 Tool에서 만든 결과가 데이터로 남고, 그 데이터가 Runtime 화면에서 다시 사용되기까지의 전체 흐름을 이해하기 시작했습니다.
MFC-Crazy-Arcade는 이후 DirectX11과 Unreal 프로젝트에서 Editor, Save / Load, Runtime Data Flow를 볼 때 화면만 보는 것이 아니라 State와 Data가 어디에서 만들어지고 어디에서 다시 사용되는지 확인하게 만든 초기 경험으로 정리하고 있습니다.