Company
교육 철학

Editor and imgui (에디터와 imgui)

Editor와 ImGui: 게임 엔진 개발 도구 구축

게임 엔진의 에디터는 개발자가 게임을 시각적으로 제작하고 디버깅할 수 있게 해주는 핵심 도구입니다. Unity와 Unreal Engine의 성공은 강력한 에디터 덕분이라고 해도 과언이 아닙니다. 이 문서에서는 에디터의 중요성을 이해하고, ImGui를 사용하여 실용적인 에디터 UI를 구축하는 방법을 상세히 다룹니다.

게임 엔진 에디터의 필요성

게임 엔진 에디터는 단순한 도구가 아니라 개발 생산성을 결정하는 핵심 요소입니다.

에디터란 무엇인가

에디터는 게임 엔진에 내장된 통합 개발 환경(IDE)으로, 코드 작성 없이도 게임의 다양한 요소를 시각적으로 구성하고 조정할 수 있게 해줍니다.

에디터의 핵심 기능

레벨 디자인 (Level Design)
게임의 월드나 맵을 시각적으로 설계하는 기능입니다.
오브젝트 배치: 드래그 앤 드롭으로 건물, 캐릭터, 소품 등을 씬에 배치
지형 편집: 브러시 도구로 산, 계곡, 평야 등 지형을 조성
조명 설정: 태양광, 포인트 라이트, 스포트라이트를 배치하고 속성 조정
이펙트 배치: 파티클 시스템, 포그, 날씨 효과를 추가하고 실시간으로 확인
자산 관리 (Asset Management)
게임에 필요한 모든 리소스를 중앙에서 관리합니다.
프로젝트 브라우저: 폴더 구조로 에셋 정리 (모델, 텍스처, 사운드, 스크립트)
임포트 시스템: 외부 파일(FBX, PNG, WAV)을 엔진 포맷으로 변환
에셋 프리뷰: 텍스처, 모델, 애니메이션을 선택하면 즉시 미리보기
메타데이터 관리: 임포트 설정, 압축 옵션, 최적화 설정 저장
스크립팅 및 코드 통합
비주얼 스크립팅이나 코드를 오브젝트에 연결하여 동작을 부여합니다.
컴포넌트 시스템: 스크립트를 오브젝트에 드래그 앤 드롭으로 추가
인스펙터 노출: 스크립트 변수를 에디터에서 실시간으로 수정
핫 리로드: 코드 수정 시 게임 재시작 없이 즉시 반영
비주얼 스크립팅: 노드 기반 그래프로 로직 구성 (Unreal Blueprint)
// 스크립트 예시: 에디터에서 노출되는 변수 class PlayerController : public Component { public: // 에디터에서 수정 가능 float moveSpeed = 5.0f; float jumpForce = 10.0f; bool enableDoubleJump = true; // 에디터에서 오브젝트 참조 연결 GameObject* targetEnemy = nullptr; }; // 에디터 인스펙터에서 보이는 내용: // Move Speed: [5.0] (슬라이더) // Jump Force: [10.0] (입력 필드) // Enable Double Jump: [✓] (체크박스) // Target Enemy: [드롭 영역] (오브젝트 참조)
C++
복사
UI 및 HUD 디자인
게임 인터페이스를 시각적으로 배치하고 디자인합니다.
캔버스 시스템: UI 요소를 화면에 배치하고 앵커 설정
위젯 에디터: 버튼, 텍스트, 이미지 등을 드래그 앤 드롭으로 배치
애니메이션 타임라인: UI 전환 효과를 프레임 단위로 제작
반응형 디자인: 다양한 해상도에서 UI가 어떻게 보이는지 미리보기
테스트 및 디버깅
실시간으로 게임을 테스트하고 문제를 진단합니다.
플레이 모드: 에디터에서 바로 게임 실행 및 테스트
일시정지 및 프레임 단위 진행: 특정 순간을 상세히 분석
런타임 인스펙터: 실행 중 오브젝트 속성 실시간 확인 및 수정
프로파일러: CPU, GPU, 메모리 사용량 분석
디버그 드로우: 충돌 박스, 레이캐스트, 경로 등을 시각화

에디터가 필요한 이유

생산성 향상

코드 없는 빠른 프로토타이핑
레벨 디자인 효율성

즉각적인 피드백

WYSIWYG (What You See Is What You Get)
에디터에서 보는 것이 실제 게임과 동일합니다.
실시간 수정
// 게임 실행 중 (Play Mode) void Update() { // 인스펙터에서 moveSpeed를 실시간으로 변경 가능 transform.position += direction * moveSpeed * deltaTime; } // 게임을 멈추지 않고: // moveSpeed: 5.0 → 너무 느림 // moveSpeed: 10.0 → 적당함 // moveSpeed: 20.0 → 너무 빠름 // 즉시 피드백으로 최적값 찾기
C++
복사

협업 효율성 증가

역할 분담
역할
작업
필요한 기술
프로그래머
게임 시스템, 물리, AI 구현
C++, C#, 알고리즘
레벨 디자이너
맵 디자인, 오브젝트 배치
에디터 사용법, 디자인 감각
아티스트
3D 모델, 텍스처, 애니메이션
3D 모델링, 포토샵
사운드 디자이너
음악, 효과음, 음향 효과
음악 이론, 오디오 편집
에디터가 있으면 각 역할이 독립적으로 작업 가능

디버깅과 최적화

비주얼 디버깅
// 충돌 박스 시각화 void OnDrawGizmos() { // 에디터에서만 보이는 디버그 드로우 Gizmos.DrawWireCube(position, size); Gizmos.DrawLine(start, end); Gizmos.DrawSphere(targetPosition, 0.5f); } // 에디터 Scene View에서 보이는 것: // - 캐릭터 주변의 충돌 박스 (녹색 와이어프레임) // - 레이캐스트 라인 (빨간 선) // - 목표 지점 (파란 구체)
C++
복사
프로파일러

사용자 정의 및 확장성

커스텀 에디터 툴
// 레벨 생성 툴 예시 class LevelGeneratorTool { public: void OnGUI() { ImGui::Text("Level Generator"); ImGui::InputInt("Width", &width); ImGui::InputInt("Height", &height); ImGui::InputFloat("Density", &density); if (ImGui::Button("Generate")) { GenerateLevel(width, height, density); } } private: void GenerateLevel(int w, int h, float d) { for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { if (Random() < d) { SpawnObstacle(x, y); } } } } int width = 10; int height = 10; float density = 0.3f; }; // 사용: // [Level Generator] 메뉴 클릭 // Width: 50 // Height: 50 // Density: 0.4 // [Generate] 버튼 클릭 // → 자동으로 50x50 레벨 생성
C++
복사

대표적인 게임 엔진 에디터

Unity Editor

특징
직관적인 인터페이스: 드래그 앤 드롭 기반의 쉬운 조작
컴포넌트 시스템: 오브젝트에 기능을 조립하듯이 추가
Play Mode: 에디터에서 바로 게임 실행 및 테스트
Asset Store: 수천 개의 에셋과 플러그인
주요 창
Scene View: 3D 공간에서 오브젝트 배치 및 조작
Game View: 플레이어가 보는 화면 미리보기
Hierarchy: 씬의 모든 오브젝트 트리 구조
Inspector: 선택한 오브젝트의 프로퍼티 편집
Project: 프로젝트의 모든 에셋 관리
Console: 로그, 경고, 에러 메시지 표시

Unreal Engine Editor

특징
고품질 그래픽: AAA 게임 수준의 시각적 표현
Blueprint: 비주얼 스크립팅으로 코드 없이 로직 구성
실시간 렌더링: 최종 게임과 동일한 퀄리티로 에디터에서 확인
머티리얼 에디터: 노드 기반 셰이더 제작
주요 창
Viewport: 3D 씬 편집 및 내비게이션
Content Browser: 에셋 관리 및 임포트
World Outliner: 레벨의 액터 계층구조
Details: 액터 프로퍼티 상세 설정
Blueprint Editor: 비주얼 스크립팅 그래프
Sequencer: 시네마틱 및 애니메이션 타임라인

에디터 개발 시 주의사항

주의할점
에디터 개발에 지나치게 집중하다 보면, 본래 게임이나 프로그램의 목표를 벗어나 기능이 과도하게 많거나, 불필요한 인터페이스 요소가 추가되는 경우가 생길 수 있습니다. 이런 상황은 에디터 기능이 본 프로젝트의 목적보다 우선시되면서, 정작 중요한 게임플레이와 핵심 기능 개발이 지연되거나 소홀히 다루어질 수 있다는 문제를 야기합니다.
이를 방지하기 위한 방법으로는 다음과 같은 점들을 고려해 볼 수 있습니다:
프로젝트의 주요 목표 설정
처음부터 명확한 목표를 세우고, 에디터 개발의 범위를 프로그램 본질과 일치시키는 것이 중요합니다.
에디터의 필수 기능과 부가 기능 구분
MVP (Minimum Viable Product) 접근 방식을 사용합니다.
사용자 피드백과 테스트 반영
실제 사용자 관점에서 에디터를 평가합니다.
단계별 기능 릴리스
작은 단위로 기능을 추가하고 검증합니다.
에디터가 게임이나 프로그램의 본질을 돕는 도구로서 역할을 하도록 주기적으로 검토하고 조정하는 것이 중요합니다.

ImGui 통합: 실용적인 에디터 UI 구축

ImGui(Immediate Mode GUI)는 빠르고 간단하게 에디터 UI를 만들 수 있는 라이브러리입니다.

ImGui의 장점

간결한 코드
// ImGui를 사용한 버튼 if (ImGui::Button("Click Me")) { // 버튼 클릭 시 실행 } // 전통적인 GUI (Win32) HWND button = CreateWindow( "BUTTON", "Click Me", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 10, 10, 100, 30, hwnd, (HMENU)ID_BUTTON, hInstance, NULL ); // WndProc에서 WM_COMMAND 처리 필요
C++
복사
즉시 모드의 장점
상태 관리 불필요
코드 흐름이 직관적
빠른 프로토타이핑
크로스 플랫폼
Windows, macOS, Linux 지원
DirectX, OpenGL, Vulkan, Metal 지원

ImGui 프로젝트 통합

1. ImGui 다운로드 및 추가

GitHub에서 다운로드
ImGui GitHub 저장소에서 최신 버전을 다운로드합니다.
필요한 파일
핵심 파일
imgui.h / imgui.cpp: ImGui 핵심 라이브러리
imgui_draw.cpp: 렌더링 데이터 생성
imgui_widgets.cpp: 버튼, 슬라이더 등 위젯
imgui_tables.cpp: 테이블 위젯
imgui_demo.cpp: 샘플 코드 (학습용)
백엔드 파일 (DirectX 11 + Win32)
imgui_impl_dx11.h / .cpp: DirectX 11 렌더링
imgui_impl_win32.h / .cpp: Win32 윈도우 처리

2. Visual Studio 프로젝트에 추가

공유 항목 프로젝트 생성
ImGui 파일 추가
메인 프로젝트에서 참조 추가

ImGui 초기화

3. ImGui 초기화 코드

bool Application::InitializeImGui() { // 1. ImGui 컨텍스트 생성 IMGUI_CHECKVERSION(); ImGui::CreateContext(); // 2. IO 설정 ImGuiIO& io = ImGui::GetIO(); // 키보드 내비게이션 활성화 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 게임패드 내비게이션 활성화 (선택적) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // 도킹 기능 활성화 (창을 자유롭게 배치) io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 멀티 뷰포트 활성화 (창을 프로그램 밖으로 끌어낼 수 있음) io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 3. 스타일 설정 ImGui::StyleColorsDark(); // 다크 테마 // ImGui::StyleColorsLight(); // 라이트 테마 // ImGui::StyleColorsClassic(); // 클래식 테마 // 4. 멀티 뷰포트 사용 시 스타일 조정 ImGuiStyle& style = ImGui::GetStyle(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { style.WindowRounding = 0.0f; style.Colors[ImGuiCol_WindowBg].w = 1.0f; } // 5. 플랫폼 백엔드 초기화 (Win32) ImGui_ImplWin32_Init(mHwnd); // 6. 렌더러 백엔드 초기화 (DirectX 11) ya::graphics::GraphicDevice_DX11* graphicDevice = ya::graphics::GetDevice(); ID3D11Device* device = graphicDevice->GetID3D11Device().Get(); ID3D11DeviceContext* deviceContext = graphicDevice->GetID3D11DeviceContext().Get(); ImGui_ImplDX11_Init(device, deviceContext); // 7. 폰트 로드 (선택적) // io.Fonts->AddFontDefault(); // io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 16.0f); LOG_INFO("ImGui initialized"); return true; }
C++
복사
설정 플래그 상세
ImGuiConfigFlags_NavEnableKeyboard
키보드로 UI를 탐색할 수 있게 합니다.
ImGuiConfigFlags_DockingEnable
창을 자유롭게 도킹하고 배치할 수 있게 합니다.
ImGuiConfigFlags_ViewportsEnable
창을 메인 윈도우 밖으로 끌어낼 수 있게 합니다.

윈도우 메시지 처리

4. WndProc에 ImGui 메시지 전달

// imgui_impl_win32.h에 선언된 함수 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // ImGui가 메시지를 먼저 처리 if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) return true; switch (message) { case WM_SIZE: { // 윈도우 크기 변경 시 그래픽 디바이스 리사이즈 if (wParam != SIZE_MINIMIZED) { application.ResizeGraphicDevice(); } break; } case WM_DPICHANGED: { // DPI 변경 시 창 위치 조정 (고해상도 모니터 지원) if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) { const RECT* suggested_rect = (RECT*)lParam; ::SetWindowPos( hWnd, NULL, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE ); } break; } case WM_DESTROY: { PostQuitMessage(0); break; } default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
C++
복사
ImGui_ImplWin32_WndProcHandler의 역할
ImGui가 다음과 같은 입력을 처리합니다:
마우스: 클릭, 드래그, 스크롤
키보드: 텍스트 입력, 단축키
포커스: 창 활성화/비활성화
// ImGui가 처리하는 메시지 예시 WM_LBUTTONDOWN // 왼쪽 마우스 버튼 클릭 WM_RBUTTONDOWN // 오른쪽 마우스 버튼 클릭 WM_MOUSEWHEEL // 마우스 휠 스크롤 WM_MOUSEMOVE // 마우스 이동 WM_KEYDOWN // 키 입력 WM_CHAR // 문자 입력 WM_SETFOCUS // 포커스 받음 WM_KILLFOCUS // 포커스 잃음
C++
복사

ImGui 렌더링 루프

5. 메인 루프에서 ImGui 렌더링

void Application::Run() { MSG msg = {}; while (true) { // 1. 윈도우 메시지 처리 if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { // 2. 게임 로직 업데이트 Update(); // 3. 게임 렌더링 Render(); // 4. ImGui 렌더링 RenderImGui(); // 5. 화면에 표시 Present(); } } } void Application::RenderImGui() { // 1. ImGui 새 프레임 시작 ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); // 2. UI 그리기 DrawEditorUI(); // 3. 렌더링 데이터 생성 ImGui::Render(); // 4. DirectX로 렌더링 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); // 5. 멀티 뷰포트 업데이트 ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); } } void Application::DrawEditorUI() { // ImGui 데모 창 (학습용) ImGui::ShowDemoWindow(); // 커스텀 에디터 창 DrawCustomEditor(); } void Application::DrawCustomEditor() { ImGui::Begin("My Editor"); ImGui::Text("Hello, ImGui!"); static float value = 0.0f; ImGui::SliderFloat("Value", &value, 0.0f, 1.0f); if (ImGui::Button("Click Me")) { LOG_INFO("Button clicked! Value: {}", value); } ImGui::End(); }
C++
복사

ImGui 메모리 해제

6. 종료 시 정리

void Application::Release() { // 1. ImGui 백엔드 정리 ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); // 2. ImGui 컨텍스트 파괴 ImGui::DestroyContext(); // 3. 게임 엔진 리소스 해제 // (조립의 역순으로 해제) ReleaseGameResources(); LOG_INFO("Application released"); }
C++
복사

ImGui 작동 원리: 즉시 모드 GUI

ImGui는 전통적인 GUI와 다른 즉시 모드(Immediate Mode) 방식을 사용합니다.

즉시 모드 vs 보존 모드

보존 모드 GUI (Retained Mode)
전통적인 GUI 라이브러리(Win32, Qt, WPF)가 사용하는 방식입니다.
// 보존 모드 예시 (Win32) // 1. UI 요소 생성 (한 번만) HWND button = CreateWindow( "BUTTON", "Click Me", WS_VISIBLE | WS_CHILD, 10, 10, 100, 30, hwnd, (HMENU)ID_BUTTON, hInstance, NULL ); // 2. 이벤트 핸들러에서 처리 LRESULT CALLBACK WndProc(...) { switch (message) { case WM_COMMAND: if (LOWORD(wParam) == ID_BUTTON) { // 버튼 클릭 처리 } break; } } // 특징: // - UI 요소가 메모리에 계속 존재 // - 상태를 시스템이 관리 // - 복잡한 이벤트 처리 필요
C++
복사
즉시 모드 GUI (Immediate Mode)
ImGui가 사용하는 방식입니다.
// 즉시 모드 예시 (ImGui) // 매 프레임마다 실행 void OnGUI() { if (ImGui::Button("Click Me")) { // 버튼 클릭 시 바로 처리 } } // 특징: // - UI를 매 프레임 다시 그림 // - 상태를 직접 관리 // - 코드 흐름이 직관적
C++
복사

ImGui 작동 단계

1단계: 매 프레임 UI 구성
void EditorLayer::OnImGuiRender() { // 매 프레임 실행 ImGui::Begin("Inspector"); // UI 요소 정의 ImGui::Text("Transform"); ImGui::DragFloat3("Position", &position.x); ImGui::DragFloat3("Rotation", &rotation.x); ImGui::DragFloat3("Scale", &scale.x); if (ImGui::Button("Reset")) { position = Vector3::Zero; rotation = Vector3::Zero; scale = Vector3::One; } ImGui::End(); } // 실행 흐름: // Frame 1: Begin → Text → DragFloat3 × 3 → Button → End // Frame 2: Begin → Text → DragFloat3 × 3 → Button → End // Frame 3: Begin → Text → DragFloat3 × 3 → Button → End // ...
C++
복사
2단계: 입력 처리
// ImGui 내부 동작 (개념적) bool ImGui::Button(const char* label) { // 1. 버튼 영역 계산 ImVec2 pos = GetCursorScreenPos(); ImVec2 size = CalcItemSize(ImVec2(0, 0), 0.0f, 0.0f); ImRect bb(pos, pos + size); // 2. 마우스 입력 확인 bool hovered = IsMouseHoveringRect(bb.Min, bb.Max); bool clicked = hovered && IsMouseClicked(0); // 3. 상태에 따라 색상 결정 ImVec4 color = clicked ? activeColor : hovered ? hoveredColor : normalColor; // 4. DrawList에 추가 (실제 렌더링 X) RenderFrame(bb.Min, bb.Max, color, true, 0.0f); RenderText(bb.Min + style.FramePadding, label); // 5. 클릭 여부 반환 return clicked; }
C++
복사
3단계: 렌더링 데이터 생성 (DrawList)
// ImGui는 DrawList에 렌더링 명령을 저장 struct ImDrawList { // 버텍스 버퍼 std::vector<ImDrawVert> VtxBuffer; // 인덱스 버퍼 std::vector<ImDrawIdx> IdxBuffer; // 렌더링 명령 std::vector<ImDrawCmd> CmdBuffer; }; // 예시: 버튼 하나를 그리기 위한 데이터 DrawList->AddRectFilled( ImVec2(10, 10), // 시작 위치 ImVec2(110, 40), // 끝 위치 IM_COL32(100, 100, 200, 255) // 색상 (RGBA) ); DrawList->AddText( ImVec2(30, 15), // 텍스트 위치 IM_COL32(255, 255, 255, 255), // 흰색 "Click Me" // 텍스트 );
C++
복사
4단계: 백엔드 렌더링
// imgui_impl_dx11.cpp의 렌더링 함수 (개념적) void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) { for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; // 1. 버텍스 버퍼 업데이트 D3D11_MAPPED_SUBRESOURCE vtx_resource; context->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource); memcpy(vtx_resource.pData, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); context->Unmap(vertexBuffer, 0); // 2. 인덱스 버퍼 업데이트 D3D11_MAPPED_SUBRESOURCE idx_resource; context->Map(indexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource); memcpy(idx_resource.pData, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); context->Unmap(indexBuffer, 0); // 3. 렌더링 명령 실행 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; // 셰이더 설정 context->VSSetShader(vertexShader, NULL, 0); context->PSSetShader(pixelShader, NULL, 0); // 텍스처 설정 context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); // 드로우 콜 context->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset, pcmd->VtxOffset); } } }
C++
복사
5단계: 다음 프레임 준비
// 프레임 종료 시 ImGui::EndFrame(); // ImGui 내부에서: // - DrawList 초기화 // - 입력 상태 초기화 // - 임시 데이터 정리 // 다음 프레임에서 모든 UI를 다시 정의
C++
복사

즉시 모드의 장점

간결한 코드

// 보존 모드 (Win32): 약 50줄 class MyDialog { HWND dialog; HWND nameEdit; HWND ageEdit; HWND submitButton; public: void Create(HWND parent) { dialog = CreateWindow(...); nameEdit = CreateWindow(...); ageEdit = CreateWindow(...); submitButton = CreateWindow(...); } void OnCommand(WPARAM wParam) { if (LOWORD(wParam) == ID_SUBMIT_BUTTON) { // 처리 } } // ... 더 많은 코드 }; // 즉시 모드 (ImGui): 약 10줄 void DrawDialog() { ImGui::Begin("My Dialog"); static char name[256] = ""; static int age = 0; ImGui::InputText("Name", name, sizeof(name)); ImGui::InputInt("Age", &age); if (ImGui::Button("Submit")) { // 처리 } ImGui::End(); }
C++
복사

상태 관리 간편

// 슬라이더 값이 변경되었을 때 다른 UI 업데이트 static float volume = 0.5f; ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f); // 조건부로 다른 UI 표시 if (volume > 0.0f) { ImGui::Text("Sound is enabled"); ImGui::SliderFloat("Bass", &bass, 0.0f, 1.0f); ImGui::SliderFloat("Treble", &treble, 0.0f, 1.0f); } else { ImGui::Text("Sound is muted"); } // 보존 모드였다면: // - volume 변경 이벤트 처리 // - bass, treble 위젯 동적 생성/파괴 // - 레이아웃 재계산 // → 복잡한 상태 관리 필요
C++
복사

빠른 프로토타이핑

// 5분 만에 만드는 레벨 에디터 void LevelEditorGUI() { ImGui::Begin("Level Editor"); // 툴 선택 static int currentTool = 0; ImGui::RadioButton("Place", &currentTool, 0); ImGui::RadioButton("Delete", &currentTool, 1); ImGui::RadioButton("Move", &currentTool, 2); // 오브젝트 종류 static int objectType = 0; ImGui::Combo("Object", &objectType, "Wall\0Floor\0Enemy\0Item\0"); // 그리드 설정 static bool showGrid = true; ImGui::Checkbox("Show Grid", &showGrid); static float gridSize = 1.0f; ImGui::SliderFloat("Grid Size", &gridSize, 0.5f, 2.0f); ImGui::End(); }
C++
복사

요약

주제
핵심 내용
에디터의 역할
레벨 디자인, 자산 관리, 스크립팅, UI 디자인, 테스트 및 디버깅을 시각적으로 수행할 수 있게 하는 통합 개발 환경
에디터의 필요성
생산성 향상 (10배 이상), 즉각적인 피드백, 팀 협업 효율성, 디버깅 도구, 확장성
주의사항
에디터 개발에 과도하게 집중하지 않도록 명확한 목표 설정, 필수/부가 기능 구분, 단계별 릴리스
ImGui 통합
GitHub에서 다운로드 → Visual Studio에 추가 → 초기화 → 메시지 처리 → 렌더링 루프 → 메모리 해제
즉시 모드 GUI
매 프레임 UI를 다시 그리는 방식. 간결한 코드, 직관적인 흐름, 빠른 프로토타이핑이 장점
작동 원리
UI 구성 → 입력 처리 → DrawList 생성 → 백엔드 렌더링 → 다음 프레임 준비
ImGui를 사용하면 복잡한 GUI 프레임워크 없이도 빠르고 효율적으로 에디터 UI를 만들 수 있습니다. 즉시 모드 방식 덕분에 코드가 직관적이고 유지보수가 쉬우며, 게임 엔진 개발에 이상적인 선택입니다.