- Created EditorConsoleSink (implements ILogSink interface) - EditorConsoleSink stores logs in memory buffer (max 1000 entries) - Added to Debug::Logger in Application::Initialize() - ConsolePanel now reads from EditorConsoleSink via static GetInstance() - Removed separate LogSystem singleton - Removed editor/src/Core/LogEntry.h (no longer needed) Now Editor and Engine share the same Debug::Logger, with ConsolePanel displaying logs via EditorConsoleSink.
38 KiB
UI-Editor 设计与实现文档
版本: 1.0
日期: 2026-03-20
目标: 为 XCEngine 游戏引擎搭建 UI 编辑器框架
第一章 概述
1.1 UI编辑器目标与定位
UI 编辑器是 XCEngine 游戏引擎的编辑器前端,用于可视化编辑游戏场景、场景层级、检视组件属性、控制台输出等核心功能。
核心目标:
- 提供独立的 UI 编辑器可执行程序(基于 ImGui + D3D12)
- UI 编辑器的数据结构与引擎核心类型对齐
- 引擎核心已有的类型直接复用,引擎核心未实现的则在 UI 编辑器中临时实现但保持接口一致
- 支持场景层级管理、实体创建删除、组件编辑等基础功能
定位:
- UI 编辑器作为引擎的独立模块,不直接耦合引擎渲染管线
- 通过 Engine 核心的抽象接口与引擎通信
- 当前阶段以独立开发为主,待引擎核心完善后进行对接
1.2 与引擎核心的对齐策略
| Engine 类型 | 状态 | UI 编辑器策略 |
|---|---|---|
XCEngine::Core::Event<T> |
✅ 已实现 | 直接复用 |
XCEngine::Core::uint64 |
✅ 已实现 | 直接复用 |
XCEngine::Debug::Logger |
✅ 已实现 | 直接复用 |
XCEngine::Debug::LogLevel |
✅ 已实现 | 直接复用 |
XCEngine::Debug::LogEntry |
✅ 已实现 | 直接复用 |
XCEngine::Math::Vector3 等 |
仅有设计文档 | UI 编辑器临时实现但接口对齐 |
Component |
仅有设计文档 | UI 编辑器自行实现 UI::Component |
GameObject |
仅有设计文档 | UI 编辑器自行实现 UI::Entity |
TransformComponent |
仅有设计文档 | UI 编辑器自行实现 UI::TransformComponent |
Scene / SceneManager |
仅有设计文档 | UI 编辑器自行实现 UI::SceneManager |
对齐原则:
- Engine 已有类型:直接
#include <XCEngine/...>并使用 - Engine 暂无类型:在 UI 编辑器中实现,但类名、成员变量、成员函数命名与设计文档保持一致
- Engine 实现后:UI 编辑器可平滑迁移到 Engine 类型
1.3 技术选型
渲染后端:D3D12
- 与引擎核心渲染管线技术栈一致
- 支持多窗口、多渲染目标
- 提供高性能的 GPU 命令提交
UI 框架:Dear ImGui
- 轻量级、可扩展的即时模式 UI
- 支持主题定制
- 成熟的 D3D12 集成示例
- 高效的 UI 渲染管线
架构模式:模块化 Manager + Panel
- Manager:负责数据管理和业务逻辑
- Panel:负责 UI 展示和用户交互
- 清晰的职责分离便于维护和扩展
第二章 架构设计
2.1 整体架构图
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ UI 编辑器架构 │
└─────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ Application │ 应用程序入口
│ (D3D12 + ImGui)│
└────────┬────────┘
│
┌─────────────────────────────────┼─────────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Managers │ │ Panels │ │ Core Types │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │SceneManager │ │ │ │HierarchyPanel│ │ │ │ Entity │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │SelectionMgr │ │◀──────────────│ │InspectorPanel│ │ │ │ Component │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ LogSystem │ │ │ │SceneViewPanel│ │ │ │ Theme │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ │
│ │ProjectManager│ │ │ │GameViewPanel │ │ │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ │
│ │ AssetItem │ │ │ │ConsolePanel │ │ │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ │
│ │ │ ┌─────────────┐ │ │ │
│ │ │ │ ProjectPanel│ │ │ │
│ │ │ └─────────────┘ │ │ │
│ │ │ ┌─────────────┐ │ │ │
│ │ │ │ MenuBar │ │ │ │
│ │ │ └─────────────┘ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ ┌───────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Engine Core (XCEngine) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │Event<T> │ │Logger │ │LogLevel │ │LogEntry │ │
│ │(已实现复用) │ │(已实现复用) │ │(已实现复用) │ │(已实现复用) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │Math Types │ │Component │ │GameObject │ │Scene │ │
│ │(设计文档) │ │(设计文档) │ │(设计文档) │ │(设计文档) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────┘
2.2 目录结构
ui_editor/
├── CMakeLists.txt # 构建配置
├── bin/ # 编译输出
│ └── Release/
│ └── XCVolumeRendererUI2.exe
├── build/ # 中间文件
└── src/
├── main.cpp # 程序入口
├── Application.h/cpp # 应用程序类(D3D12 + ImGui)
│
├── Core/ # 核心数据类型
│ ├── GameObject.h # Entity、Component、TransformComponent
│ ├── LogEntry.h # 日志条目(复用 Engine LogLevel)
│ └── AssetItem.h # 资产条目
│
├── Managers/ # 管理器系统
│ ├── SceneManager.h/cpp # 场景管理
│ ├── SelectionManager.h # 选择管理
│ ├── LogSystem.h/cpp # 日志系统
│ └── ProjectManager.h/cpp # 项目管理
│
├── panels/ # UI 面板
│ ├── Panel.h/cpp # 面板基类
│ ├── MenuBar.h/cpp # 菜单栏
│ ├── HierarchyPanel.h/cpp # 层级面板
│ ├── InspectorPanel.h/cpp # 检视面板
│ ├── SceneViewPanel.h/cpp # 场景视图
│ ├── GameViewPanel.h/cpp # 游戏视图
│ ├── ConsolePanel.h/cpp # 控制台面板
│ └── ProjectPanel.h/cpp # 项目面板
│
└── Theme.h/cpp # 主题样式
2.3 核心类型与引擎核心的对齐映射表
| UI 编辑器类型 | 文件位置 | 对齐的 Engine 类型 | 说明 |
|---|---|---|---|
UI::Entity |
Core/GameObject.h | XCEngine::GameObject |
实体,包含 ID、名称、层级关系、组件 |
UI::Component |
Core/GameObject.h | XCEngine::Component |
组件基类 |
UI::TransformComponent |
Core/GameObject.h | XCEngine::TransformComponent |
变换组件 |
UI::MeshRendererComponent |
Core/GameObject.h | XCEngine::RenderMeshComponent |
网格渲染组件 |
UI::EntityID |
Core/GameObject.h | uint64_t |
实体唯一标识符 |
UI::INVALID_ENTITY_ID |
Core/GameObject.h | N/A | 无效实体 ID 常量 |
UI::SceneManager |
Managers/SceneManager.h | XCEngine::SceneManager |
场景管理器 |
UI::LogSystem |
Managers/LogSystem.h | XCEngine::Debug::Logger |
日志系统 |
UI::LogEntry |
Core/LogEntry.h | XCEngine::Debug::LogEntry |
日志条目 |
XCEngine::Core::Event<T> |
Engine/include/... | N/A | 直接复用引擎事件系统 |
第三章 核心数据类型
3.1 Entity(对齐 Engine GameObject)
Entity 是 UI 编辑器中的核心对象类型,对齐 Engine 的 GameObject 设计。
设计文件:ui_editor/src/Core/GameObject.h
namespace UI {
using EntityID = uint64_t;
constexpr EntityID INVALID_ENTITY_ID = 0;
class Entity {
public:
EntityID id = INVALID_ENTITY_ID;
std::string name;
EntityID parent = INVALID_ENTITY_ID; // 父实体 ID
std::vector<EntityID> children; // 子实体 ID 列表
std::vector<std::unique_ptr<Component>> components;
bool selected = false;
template<typename T, typename... Args>
T* AddComponent(Args&&... args) {
auto comp = std::make_unique<T>(std::forward<Args>(args)...);
comp->m_entity = this;
T* ptr = comp.get();
components.push_back(std::move(comp));
return ptr;
}
template<typename T>
T* GetComponent() {
for (auto& comp : components) {
if (auto casted = dynamic_cast<T*>(comp.get())) {
return casted;
}
}
return nullptr;
}
template<typename T>
std::vector<T*> GetComponents() {
std::vector<T*> result;
for (auto& comp : components) {
if (auto casted = dynamic_cast<T*>(comp.get())) {
result.push_back(casted);
}
}
return result;
}
};
} // namespace UI
关键设计决策:
- EntityID 类型:使用
uint64_t作为实体唯一标识,与 Engine 的uint64_t一致 - 父子关系:通过
parentID 和childrenID 列表维护层级关系,避免循环引用 - 组件存储:使用
std::vector<std::unique_ptr<Component>>存储组件,支持多态 - 选择状态:
selected成员用于追踪实体是否被选中
与 Engine GameObject 的接口对齐:
| UI::Entity 接口 | Engine::GameObject 接口 | 对齐状态 |
|---|---|---|
id |
(无直接对应,Engine 用指针) | 接口不同但功能一致 |
name |
name |
✅ 完全对齐 |
parent |
GetParent()/SetParent() |
✅ 功能对齐 |
children |
GetChildren() |
✅ 功能对齐 |
AddComponent<T>() |
AddComponent<T>() |
✅ 接口对齐 |
GetComponent<T>() |
GetComponent<T>() |
✅ 接口对齐 |
3.2 Component(对齐 Engine Component)
设计文件:ui_editor/src/Core/GameObject.h
class Component {
public:
virtual ~Component() = default;
virtual std::string GetName() const = 0;
virtual void Awake() {}
virtual void Start() {}
virtual void Update(float deltaTime) {}
virtual void OnDestroy() {}
class Entity* GetEntity() const { return m_entity; }
bool IsEnabled() const { return m_enabled; }
void SetEnabled(bool enabled) { m_enabled = enabled; }
protected:
class Entity* m_entity = nullptr;
bool m_enabled = true;
friend class Entity;
};
生命周期函数:对齐 Engine Component 的设计,包含 Awake()、Start()、Update()、OnDestroy() 等。
TransformComponent 实现:
class TransformComponent : public Component {
public:
float position[3] = {0.0f, 0.0f, 0.0f};
float rotation[3] = {0.0f, 0.0f, 0.0f};
float scale[3] = {1.0f, 1.0f, 1.0f};
std::string GetName() const override { return "Transform"; }
};
MeshRendererComponent 实现:
class MeshRendererComponent : public Component {
public:
std::string materialName = "Default-Material";
std::string meshName = "";
std::string GetName() const override { return "Mesh Renderer"; }
};
3.3 ComponentRegistry(组件注册表)
组件注册表用于将组件类型与对应的 ImGui 检视函数关联。
using ComponentInspectorFn = std::function<void(Component*)>;
struct ComponentInspectorInfo {
std::string name;
ComponentInspectorFn renderFn;
};
class ComponentRegistry {
public:
static ComponentRegistry& Get() {
static ComponentRegistry instance;
return instance;
}
template<typename T>
void RegisterComponent(const std::string& name, ComponentInspectorFn inspectorFn) {
m_inspectors[name] = {name, inspectorFn};
m_factories[name] = []() -> std::unique_ptr<Component> {
return std::make_unique<T>();
};
}
ComponentInspectorInfo* GetInspector(const std::string& name) {
auto it = m_inspectors.find(name);
if (it != m_inspectors.end()) {
return &it->second;
}
return nullptr;
}
private:
ComponentRegistry() = default;
std::unordered_map<std::string, ComponentInspectorInfo> m_inspectors;
std::unordered_map<std::string, std::function<std::unique_ptr<Component>()>> m_factories;
};
注册示例(在 InspectorPanel.cpp 中):
ComponentRegistry::Get().RegisterComponent<TransformComponent>(
"Transform",
[](Component* comp) {
auto* transform = dynamic_cast<TransformComponent*>(comp);
ImGui::InputFloat3("Position", transform->position);
ImGui::InputFloat3("Rotation", transform->rotation);
ImGui::InputFloat3("Scale", transform->scale);
}
);
3.4 SceneManager(对齐 Engine SceneManager)
设计文件:ui_editor/src/Managers/SceneManager.h
class SceneManager {
public:
static SceneManager& Get() {
static SceneManager instance;
return instance;
}
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY_ID);
Entity* GetEntity(EntityID id) {
auto it = m_entities.find(id);
if (it != m_entities.end()) {
return &it->second;
}
return nullptr;
}
const std::vector<EntityID>& GetRootEntities() const {
return m_rootEntities;
}
void DeleteEntity(EntityID id);
void RenameEntity(EntityID id, const std::string& newName);
void CopyEntity(EntityID id);
EntityID PasteEntity(EntityID parent = INVALID_ENTITY_ID);
EntityID DuplicateEntity(EntityID id);
void MoveEntity(EntityID id, EntityID newParent);
void CreateDemoScene();
XCEngine::Core::Event<EntityID> OnEntityCreated;
XCEngine::Core::Event<EntityID> OnEntityDeleted;
XCEngine::Core::Event<EntityID> OnEntityChanged;
XCEngine::Core::Event<> OnSceneChanged;
private:
EntityID m_nextEntityId = 1;
std::unordered_map<EntityID, Entity> m_entities;
std::vector<EntityID> m_rootEntities;
std::optional<ClipboardData> m_clipboard;
};
关键设计决策:
- Singleton 模式:通过
static SceneManager& Get()提供全局访问点 - 实体存储:
std::unordered_map<EntityID, Entity>提供 O(1) 的实体查找 - 根实体列表:
m_rootEntities维护所有顶层实体,用于层级面板展示 - 剪贴板支持:
std::optional<ClipboardData>支持复制/粘贴操作 - 事件系统:复用 Engine 的
Event<T>实现观察者模式
事件类型说明:
| 事件 | 签名 | 触发时机 |
|---|---|---|
OnEntityCreated |
Event<EntityID> |
创建新实体时 |
OnEntityDeleted |
Event<EntityID> |
删除实体时 |
OnEntityChanged |
Event<EntityID> |
实体属性变化时(重命名、父子关系变化) |
OnSceneChanged |
Event<> |
场景整体变化时 |
第四章 面板系统
4.1 Panel 基类
所有面板继承自 Panel 基类,提供统一的接口。
设计文件:ui_editor/src/panels/Panel.h
class Panel {
public:
virtual ~Panel() = default;
virtual void Initialize() {}
virtual void Render() = 0;
virtual void OnSceneChanged() {}
const char* GetName() const { return m_name; }
bool IsVisible() const { return m_visible; }
void SetVisible(bool visible) { m_visible = visible; }
protected:
const char* m_name = "Panel";
bool m_visible = true;
};
ImGui 窗口包装示例:
void HierarchyPanel::Render() {
if (!m_visible) return;
ImGui::PushID(GetName());
if (ImGui::Begin(GetName(), &m_visible, ImGuiWindowFlags_NoCollapse)) {
RenderContent();
}
ImGui::End();
ImGui::PopID();
}
4.2 HierarchyPanel(层级面板)
职责:展示场景层级结构,支持实体的创建、删除、拖拽排序、右键菜单。
设计文件:ui_editor/src/panels/HierarchyPanel.h
class HierarchyPanel : public Panel {
public:
void Initialize() override;
void OnSceneChanged() override;
private:
void RenderContent();
void RenderEntity(EntityID entity, int& nodeIndex);
void RenderContextMenu(EntityID entity);
void RenderCreateMenu();
};
核心功能:
- 树形结构展示:递归渲染实体及其子实体
- 选中高亮:选中的实体以高亮显示
- 拖拽排序:支持通过拖拽改变实体顺序和父子关系
- 右键菜单:创建、删除、复制、粘贴、重命名等操作
- 搜索过滤:支持按名称搜索实体
节点渲染流程:
RenderEntity(EntityID id)
│
├── 获取实体指针 GetEntity(id)
│
├── 构建节点标签 [图标] [名称] [子节点数量]
│
├── 选中状态处理
│ └── 点击时调用 SelectionManager::Select(id)
│
├── 展开/折叠状态
│
├── 渲染子节点(递归)
│ └── for child in entity.children: RenderEntity(child)
│
└── 渲染右键菜单(如果右键)
4.3 InspectorPanel(检视面板)
职责:展示选中实体的所有组件及其属性,支持编辑。
设计文件:ui_editor/src/panels/InspectorPanel.h
class InspectorPanel : public Panel {
public:
void Initialize() override;
void OnSelectionChanged();
private:
void RenderContent();
void RenderEntityHeader(Entity* entity);
void RenderComponent(Component* comp);
void RenderAddComponentMenu();
};
核心功能:
- 实体头信息:显示实体名称,支持直接编辑
- 组件列表:遍历实体的所有组件
- 组件检视:调用
ComponentRegistry获取检视函数并渲染 - 添加组件:显示可添加的组件类型列表
组件检视函数注册示例:
void InspectorPanel::Initialize() {
ComponentRegistry::Get().RegisterComponent<TransformComponent>(
"Transform",
[](Component* comp) {
auto* transform = dynamic_cast<TransformComponent*>(comp);
ImGui::InputFloat3("Position", transform->position);
if (ImGui::InputFloat3("Rotation", transform->rotation)) {
SceneManager::Get().GetEntity(transform->GetEntity()->id)
->name = transform->GetEntity()->name; // 触发变更事件
}
ImGui::InputFloat3("Scale", transform->scale, 1.0f);
}
);
ComponentRegistry::Get().RegisterComponent<MeshRendererComponent>(
"Mesh Renderer",
[](Component* comp) {
auto* mesh = dynamic_cast<MeshRendererComponent*>(comp);
ImGui::InputText("Mesh", &mesh->meshName);
ImGui::InputText("Material", &mesh->materialName);
}
);
}
4.4 SceneViewPanel(场景视图)
职责:渲染场景视图窗口,提供视口控制。
设计文件:ui_editor/src/panels/SceneViewPanel.h
当前实现状态:基础框架已搭建,待扩展。
计划功能:
- 视口渲染(通过 Engine 渲染管线)
- 相机控制(平移、旋转、缩放)
- Gizmos 渲染(变换、旋转、缩放工具)
- 网格和辅助线显示
4.5 GameViewPanel(游戏视图)
职责:显示游戏运行时的画面。
设计文件:ui_editor/src/panels/GameViewPanel.h
当前实现状态:基础框架已搭建,待与 Engine 渲染管线对接。
4.6 ConsolePanel(控制台)
职责:显示日志系统收集的日志消息。
设计文件:ui_editor/src/panels/ConsolePanel.h/cpp
class ConsolePanel : public Panel {
public:
void Initialize() override;
void Clear();
void OnLogMessage(const LogEntry& entry);
private:
void RenderContent();
void RenderLogEntry(const LogEntry& entry);
void RenderFilterBar();
std::vector<LogEntry> m_logs;
std::vector<LogEntry> m_filteredLogs;
bool m_autoScroll = true;
bool m_wordWrap = false;
XCEngine::Debug::LogLevel m_minLevel = XCEngine::Debug::LogLevel::Verbose;
};
核心功能:
- 日志显示:显示所有收集的日志条目
- 级别过滤:通过下拉菜单筛选日志级别
- 自动滚动:新日志自动滚动到底部
- 时间戳显示:显示每条日志的时间戳
- 双击跳转:双击日志可定位到相关实体(预留)
4.7 ProjectPanel(项目面板)
职责:浏览项目资源文件。
设计文件:ui_editor/src/panels/ProjectPanel.h/cpp
当前实现状态:基础框架已搭建,待扩展资源导入功能。
第五章 管理器系统
5.1 SelectionManager(选择管理器)
设计文件:ui_editor/src/Managers/SelectionManager.h
class SelectionManager {
public:
static SelectionManager& Get() {
static SelectionManager instance;
return instance;
}
void Select(EntityID entity);
void Deselect(EntityID entity);
void ToggleSelection(EntityID entity);
void ClearSelection();
void SetSelection(const std::vector<EntityID>& entities);
bool IsSelected(EntityID entity) const;
const std::vector<EntityID>& GetSelection() const { return m_selection; }
size_t GetSelectionCount() const { return m_selection.size(); }
XCEngine::Core::Event<EntityID> OnSelected;
XCEngine::Core::Event<EntityID> OnDeselected;
XCEngine::Core::Event<> OnSelectionCleared;
private:
SelectionManager() = default;
std::vector<EntityID> m_selection;
std::unordered_set<EntityID> m_selectionSet;
};
关键设计决策:
- 双向存储:
m_selection保持顺序,m_selectionSet提供 O(1) 查询 - 事件系统:选择变化时触发对应事件
- 多选支持:通过
SetSelection支持批量选择
5.2 LogSystem(日志系统)
设计文件:ui_editor/src/Managers/LogSystem.h/cpp
class LogSystem {
public:
static LogSystem& Get() {
static LogSystem instance;
return instance;
}
void Initialize();
void Shutdown();
void Log(XCEngine::Debug::LogLevel level, const std::string& message,
const std::string& file = "", int line = 0);
void Info(const std::string& message) { Log(LogLevel::Info, message); }
void Warning(const std::string& message) { Log(LogLevel::Warning, message); }
void Error(const std::string& message) { Log(LogLevel::Error, message); }
XCEngine::Core::Event<const LogEntry&> OnLog;
private:
LogSystem() = default;
std::vector<LogEntry> m_logs;
};
日志流向:
XCEngine::Debug::Logger (Engine)
│
▼ (通过自定义 LogSink 拦截)
UI::LogSystem::OnLog
│
▼
ConsolePanel::OnLogMessage
│
▼
显示到 ConsolePanel
5.3 ProjectManager(项目管理器)
设计文件:ui_editor/src/Managers/ProjectManager.h/cpp
职责:
- 管理项目根目录
- 扫描和索引资源文件
- 提供资源查找接口
第六章 事件系统
6.1 引擎 Event 的复用
UI 编辑器直接复用 Engine 的事件系统:
#include <XCEngine/Core/Event.h>
// 使用方式
XCEngine::Core::Event<EntityID> OnEntityCreated;
XCEngine::Core::Event<EntityID> OnEntityDeleted;
XCEngine::Core::Event<EntityID> OnEntityChanged;
XCEngine::Core::Event<> OnSceneChanged;
订阅示例:
// 在 Panel 初始化时订阅
SceneManager::Get().OnEntityCreated.AddLambda([this](EntityID id) {
// 处理实体创建
});
6.2 UI 编辑器事件类型
| 事件源 | 事件名 | 签名 | 说明 |
|---|---|---|---|
SceneManager |
OnEntityCreated |
Event<EntityID> |
实体创建 |
SceneManager |
OnEntityDeleted |
Event<EntityID> |
实体删除 |
SceneManager |
OnEntityChanged |
Event<EntityID> |
实体属性变化 |
SceneManager |
OnSceneChanged |
Event<> |
场景变化 |
SelectionManager |
OnSelected |
Event<EntityID> |
实体被选中 |
SelectionManager |
OnDeselected |
Event<EntityID> |
实体取消选中 |
SelectionManager |
OnSelectionCleared |
Event<> |
选择被清空 |
LogSystem |
OnLog |
Event<const LogEntry&> |
日志消息 |
6.3 事件处理时机
同一帧内的事件处理:
void Application::Render() {
// 1. 处理用户输入
// 2. 更新 Managers
SceneManager::Get().Update(deltaTime);
// 3. 清空pending列表(ProcessUnsubscribes)
// 4. 渲染 ImGui UI
RenderUI();
// 5. 渲染 D3D12
RenderD3D12();
}
注意:Event<T>::ProcessUnsubscribes() 应在每帧适当位置调用,以确保安全的订阅取消。
第七章 渲染集成
7.1 D3D12 初始化流程
设计文件:ui_editor/src/Application.cpp
Initialize(HWND hwnd)
│
├── CreateDevice()
│ ├── D3D12CreateDevice()
│ ├── CreateCommandQueue()
│ ├── CreateCommandAllocator()
│ └── CreateCommandList()
│
├── CreateRenderTarget()
│ ├── CreateDescriptorHeap (RTV)
│ ├── CreateDescriptorHeap (SRV)
│ └── CreateRenderTargets (3个双缓冲)
│
└── CreateFence()
7.2 ImGui 渲染管线
初始化:
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX12_Init(
m_device,
3, // 双缓冲帧数
DXGI_FORMAT_R8G8B8A8_UNORM, // 格式
m_srvHeap,
m_srvHeap->GetCPUDescriptorHandleForHeapStart(),
m_srvHeap->GetGPUDescriptorHandleForHeapStart()
);
渲染:
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
// 渲染 ImGui UI
RenderUI();
ImGui::EndFrame();
ImGui::Render();
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), m_commandList);
7.3 渲染目标与交换链
配置:
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferCount = 3; // 三重缓冲
swapChainDesc.SampleDesc.Count = 1;
_present 流程:
m_swapChain->Present(1, 0);
m_fenceValue++;
m_commandQueue->Signal(m_fence, m_fenceValue);
第八章 主题与样式
8.1 Theme 系统
设计文件:ui_editor/src/Theme.h/cpp
struct Theme {
ImVec4 colors[ImGuiCol_COUNT];
void Apply();
void LoadDefault();
void LoadDark();
void LoadLight();
};
extern Theme g_theme;
默认深色主题配色:
| 用途 | 颜色 (RGB) |
|---|---|
| 背景 | (0.1, 0.1, 0.1) |
| 面板背景 | (0.15, 0.15, 0.15) |
| 边框 | (0.3, 0.3, 0.3) |
| 文字 | (0.9, 0.9, 0.9) |
| 选中 | (0.2, 0.4, 0.8) |
| 警告 | (0.9, 0.6, 0.2) |
| 错误 | (0.9, 0.2, 0.2) |
第九章 未来扩展计划
9.1 序列化/反序列化
计划实现:
class SceneSerializer {
public:
bool Serialize(Scene* scene, const String& filePath);
bool Deserialize(Scene* scene, const String& filePath);
};
文件格式:JSON 或二进制(待定)
9.2 撤销/重做系统
计划实现:
class UndoSystem {
public:
void PushAction(std::unique_ptr<IAction> action);
void Undo();
void Redo();
bool CanUndo() const;
bool CanRedo() const;
private:
std::vector<std::unique_ptr<IAction>> m_undoStack;
std::vector<std::unique_ptr<IAction>> m_redoStack;
};
支持的操作:
- 实体创建/删除
- 实体重命名
- 实体移动(父子关系变更)
- 组件添加/删除
- 属性修改
9.3 资源导入管线
计划实现:
- 资源文件监控(文件变化自动检测)
- 资源导入器(Mesh、Texture、Material 等)
- 资源依赖解析
- 资源热重载
9.4 预制体系统
计划实现:
class Prefab {
public:
String name;
std::vector<std::unique_ptr<Component>> components;
std::vector<Prefab> children;
};
附录 A:核心类型对齐详细对照表
| UI 编辑器类型/接口 | Engine 类型/接口 | 文件位置 | 对齐状态 |
|---|---|---|---|
UI::Entity |
XCEngine::GameObject |
GameObject.h / GameObject.h | ✅ 接口对齐 |
UI::EntityID |
uint64_t |
GameObject.h / Types.h | ✅ 完全一致 |
UI::INVALID_ENTITY_ID = 0 |
N/A | GameObject.h | ✅ 自定义常量 |
UI::Component |
XCEngine::Component |
GameObject.h / Component.h | ✅ 接口对齐 |
UI::Component::GetEntity() |
Component::gameObject() |
GameObject.h / Component.h | ✅ 功能一致 |
UI::TransformComponent |
XCEngine::TransformComponent |
GameObject.h / TransformComponent.h | ✅ 接口对齐 |
UI::TransformComponent::position |
TransformComponent::GetPosition() |
GameObject.h / TransformComponent.h | ✅ 成员/方法对齐 |
UI::SceneManager |
XCEngine::SceneManager |
SceneManager.h / SceneManager.h | ✅ 接口对齐 |
UI::SceneManager::CreateEntity() |
SceneManager::CreateScene() (不同) |
SceneManager.h | ⚠️ 接口有差异 |
UI::LogSystem |
XCEngine::Debug::Logger |
LogSystem.h / Logger.h | ✅ 功能复用 |
UI::LogEntry |
XCEngine::Debug::LogEntry |
LogEntry.h / LogEntry.h | ✅ 复用 Engine |
XCEngine::Core::Event<T> |
N/A | Event.h | ✅ 直接复用 |
XCEngine::Debug::LogLevel |
N/A | LogLevel.h | ✅ 直接复用 |
附录 B:事件类型清单
SceneManager 事件
| 事件名 | 类型 | 参数 | 触发时机 |
|---|---|---|---|
OnEntityCreated |
Event<EntityID> |
新实体的 ID | CreateEntity() 成功后 |
OnEntityDeleted |
Event<EntityID> |
被删实体的 ID | DeleteEntity() 成功后 |
OnEntityChanged |
Event<EntityID> |
变化实体的 ID | RenameEntity()、MoveEntity() 等 |
OnSceneChanged |
Event<> |
无 | 场景整体变化时 |
SelectionManager 事件
| 事件名 | 类型 | 参数 | 触发时机 |
|---|---|---|---|
OnSelected |
Event<EntityID> |
被选实体的 ID | Select() 时 |
OnDeselected |
Event<EntityID> |
取消选中的实体 ID | Deselect() 时 |
OnSelectionCleared |
Event<> |
无 | ClearSelection() 时 |
LogSystem 事件
| 事件名 | 类型 | 参数 | 触发时机 |
|---|---|---|---|
OnLog |
Event<const LogEntry&> |
日志条目引用 | 任意日志产生时 |
附录 C:面板布局配置
默认布局(通过 ImGui Dockspace 实现):
┌────────────────────────────────────────────────────────────────────┐
│ MenuBar │
├──────────────┬─────────────────────────────────┬─────────────────┤
│ │ │ │
│ Hierarchy │ SceneView │ Inspector │
│ Panel │ Panel │ Panel │
│ │ │ │
│ (200px) │ (flex) │ (250px) │
│ │ │ │
├──────────────┼─────────────────────────────────┼─────────────────┤
│ │ │ │
│ Project │ GameView │ Console │
│ Panel │ Panel │ Panel │
│ │ │ │
│ (200px) │ (flex) │ (150px) │
│ │ │ │
└──────────────┴─────────────────────────────────┴─────────────────┘
Dock 优先级:
- HierarchyPanel - 左上
- SceneViewPanel - 中上
- InspectorPanel - 右上
- ProjectPanel - 左下
- GameViewPanel - 中下
- ConsolePanel - 右下
文档结束