# Editor 重构计划 ## 一、当前问题总结 ### 1.1 架构问题 | 问题 | 位置 | 严重程度 | |------|------|----------| | `Panel` 滥用 `Core::Layer` 继承 | `editor/src/panels/Panel.h` | P0 | | 单例模式滥用 | 所有 Manager 类 | P1 | | 直接使用 `GameObject*` 裸指针 | 各 Panel 文件 | P1 | | `EditorSceneManager` 职责过重 | `editor/src/Managers/SceneManager.h` | P1 | | 无统一事件总线 | 整体架构 | P1 | ### 1.2 功能缺失 | 功能 | 当前状态 | |------|----------| | Undo/Redo | 完全缺失 | | 场景序列化/反序列化 | 完全缺失 | | 资源引用系统 | 完全缺失 | | Play/Edit 模式切换 | 只有框架 | | Transform Gizmos | 完全缺失 | | Inspector 组件扩展 | 仅支持 TransformComponent | | 场景/游戏视图相机控制 | 完全缺失 | ### 1.3 代码质量 - 硬编码路径(崩溃日志路径) - 调试日志残留(InspectorPanel 中大量无意义的 Debug 日志) - 内存泄漏风险(raw new 无智能指针) - 异常处理硬编码 --- ## 二、重构目标 ### 2.1 短期目标(原型验证) - [ ] 解决 P0 级架构问题 - [ ] 实现基础 Undo/Redo - [ ] 实现场景序列化 - [ ] 分离引擎核心与编辑器状态 ### 2.2 中期目标(功能完善) - [ ] 实现 Transform Gizmos - [ ] 实现 Inspector 组件扩展机制 - [ ] 实现场景/游戏视图相机控制 - [ ] 实现 Play/Edit 模式切换 - [ ] 实现资源引用系统 ### 2.3 长期目标(生产可用) - [ ] 编辑器配置序列化 - [ ] 插件系统 - [ ] 多场景编辑 - [ ] 性能优化 --- ## 三、重构方案 ### 3.1 架构重构 #### 3.1.1 Panel 独立化 **现状**: ```cpp class Panel : public Core::Layer { // ❌ 编辑器面板不是游戏层级 ``` **重构**: ```cpp namespace XCEngine { namespace Editor { class Panel { public: Panel(const std::string& name) : m_name(name), m_isOpen(true) {} virtual ~Panel() = default; virtual void OnAttach() {} virtual void OnDetach() {} virtual void OnUpdate(float dt) {} virtual void OnEvent(void* event) {} virtual void Render() = 0; bool IsOpen() const { return m_isOpen; } void SetOpen(bool open) { m_isOpen = open; } protected: std::string m_name; bool m_isOpen; }; } // namespace Editor } // namespace XCEngine ``` **理由**:`Core::Layer` 设计用于游戏层级系统(UI/World/Background),编辑器面板只是 UI 控件,不应继承它。 #### 3.1.2 单例改造为依赖注入 **现状**: ```cpp class SelectionManager { public: static SelectionManager& Get() { ... } // ❌ 单例 }; ``` **重构**: ```cpp class IEditorContext { public: virtual ~IEditorContext() = default; virtual ISelectionManager& GetSelectionManager() = 0; virtual ISceneManager& GetSceneManager() = 0; virtual IProjectManager& GetProjectManager() = 0; virtual IUndoRedoSystem& GetUndoRedoSystem() = 0; }; class EditorLayer { public: void SetContext(std::shared_ptr context) { m_context = context; } private: std::shared_ptr m_context; }; ``` #### 3.1.3 引入事件总线 **新增 `EditorEventBus`**: ```cpp class EditorEventBus { public: template void Subscribe(std::function handler); template void Unsubscribe(uint64_t id); template void Publish(const T& event); private: std::unordered_map>> m_handlers; std::unordered_map m_nextId; }; ``` **定义事件类型**: ```cpp struct SelectionChangedEvent { std::vector selectedObjects; }; struct EntityCreatedEvent { GameObjectID entityId; }; struct EntityDestroyedEvent { GameObjectID entityId; }; ``` #### 3.1.4 GameObject 生命周期管理 **现状**: ```cpp ::XCEngine::Components::GameObject* m_selectedGameObject = nullptr; // ❌ 裸指针 ``` **重构**: ```cpp using GameObjectHandle = ResourceHandle; struct SelectionState { std::vector selectedObjects; GameObjectHandle primarySelection; // 最后选中的 }; ``` --- ### 3.2 功能重构 #### 3.2.1 Undo/Redo 系统 **Command Pattern 实现**: ```cpp class ICommand { public: virtual ~ICommand() = default; virtual void Execute() = 0; virtual void Undo() = 0; virtual std::string GetName() const = 0; }; class CreateEntityCommand : public ICommand { public: CreateEntityCommand(ISceneManager& scene, GameObjectHandle parent, std::string name); void Execute() override; void Undo() override; std::string GetName() const override { return "Create " + m_name; } private: ISceneManager& m_scene; GameObjectHandle m_parent; std::string m_name; GameObjectHandle m_createdEntity; }; class DeleteEntityCommand : public ICommand { public: DeleteEntityCommand(ISceneManager& scene, GameObjectHandle entity); void Execute() override; void Undo() override; std::string GetName() const override { return "Delete " + m_entityName; } private: ISceneManager& m_scene; GameObjectHandle m_entity; std::string m_entityName; std::vector m_children; GameObjectHandle m_parent; // 存储删除前的完整状态用于恢复 }; class TransformCommand : public ICommand { public: TransformCommand(GameObjectHandle entity, const Transform& oldState, const Transform& newState); void Execute() override { Apply(m_newState); } void Undo() override { Apply(m_oldState); } private: void Apply(const Transform& t); GameObjectHandle m_entity; Transform m_oldState; Transform m_newState; }; ``` **Undo/Redo Manager**: ```cpp class UndoRedoSystem { public: void Execute(std::unique_ptr command); void Undo(); void Redo(); bool CanUndo() const { return m_undoStack.size() > m_historyIndex + 1; } bool CanRedo() const { return m_historyIndex >= 0; } private: std::vector> m_undoStack; int m_historyIndex = -1; static constexpr size_t MAX_HISTORY = 100; }; ``` #### 3.2.2 场景序列化 **Scene 序列化接口**: ```cpp class ISceneSerializer { public: virtual ~ISceneSerializer() = default; virtual bool Serialize(IScene* scene, const std::string& path) = 0; virtual bool Deserialize(IScene* scene, const std::string& path) = 0; }; class JsonSceneSerializer : public ISceneSerializer { public: bool Serialize(IScene* scene, const std::string& path) override; bool Deserialize(IScene* scene, const std::string& path) override; private: nlohmann::json GameObjectToJson(GameObject* go); GameObject* JsonToGameObject(const nlohmann::json& j, GameObject* parent); }; ``` **序列化格式(JSON)**: ```json { "version": "1.0", "name": "MainScene", "entities": [ { "id": "1234567890", "name": "Player", "components": [ { "type": "TransformComponent", "position": [0, 0, 0], "rotation": [0, 0, 0], "scale": [1, 1, 1] }, { "type": "MeshRendererComponent", "mesh": "Assets/Meshes/cube.mesh", "material": "Assets/Materials/default.mat" } ], "children": [ { "id": "9876543210", "name": "Weapon", "components": [...] } ] } ] } ``` #### 3.2.3 Inspector 组件扩展机制 **抽象 Component 编辑器**: ```cpp class IComponentEditor { public: virtual ~IComponentEditor() = default; virtual std::string GetComponentTypeName() const = 0; virtual bool CanEdit(Component* component) const = 0; virtual void Render(Component* component) = 0; }; class TransformComponentEditor : public IComponentEditor { public: std::string GetComponentTypeName() const override { return "TransformComponent"; } bool CanEdit(Component* component) const override { return dynamic_cast(component) != nullptr; } void Render(Component* component) override; }; class InspectorPanel { public: void RegisterComponentEditor(std::unique_ptr editor); void RenderGameObject(GameObject* gameObject); private: std::vector> m_editors; std::unique_ptr GetEditorFor(Component* component); }; ``` **注册默认编辑器**: ```cpp void InspectorPanel::Initialize() { RegisterComponentEditor(std::make_unique()); // 后续添加更多编辑器 } ``` #### 3.2.4 资源引用系统 **AssetHandle**: ```cpp template class AssetHandle { public: AssetHandle() = default; explicit AssetHandle(AssetID id, std::shared_ptr asset = nullptr); AssetID GetID() const { return m_id; } T* Get() const { return m_asset.get(); } T* operator->() const { return m_asset.get(); } explicit operator bool() const { return m_asset != nullptr; } private: AssetID m_id; std::shared_ptr m_asset; }; class MeshRendererComponent { public: AssetHandle GetMesh() const { return m_mesh; } void SetMesh(AssetHandle mesh) { m_mesh = mesh; } private: AssetHandle m_mesh; AssetHandle m_material; }; ``` --- ### 3.3 界面重构 #### 3.3.1 SceneView 实现 **相机控制器**: ```cpp class SceneViewCameraController { public: enum class Mode { Pan, Orbit, Zoom }; void OnUpdate(float dt); void OnMouseMove(int x, int y); void OnMouseWheel(int delta); Matrix4 GetViewMatrix() const; Matrix4 GetProjectionMatrix() const; private: Mode m_mode = Mode::Orbit; Vector3 m_target = Vector3::Zero(); float m_distance = 10.0f; float m_pitch = 0.0f; float m_yaw = 0.0f; bool m_isDragging = false; ImVec2 m_lastMousePos; }; ``` **Gizmos 渲染**: ```cpp class GizmosRenderer { public: void DrawTranslateGizmo(GameObjectHandle target); void DrawRotateGizmo(GameObjectHandle target); void DrawScaleGizmo(GameObjectHandle target); enum class Axis { X, Y, Z, XY, XZ, YZ, XYZ }; std::optional HandleInput(const Ray& ray); }; ``` #### 3.3.2 Editor 模式状态机 ```cpp enum class EditorMode { Edit, Play, Paused }; class EditorStateMachine { public: void SetMode(EditorMode mode); EditorMode GetMode() const { return m_mode; } void Update(float dt); private: EditorMode m_mode = EditorMode::Edit; void EnterEditMode(); void ExitEditMode(); void EnterPlayMode(); void ExitPlayMode(); }; ``` --- ## 四、重构实施计划 ### 阶段一:架构重构(第 1-2 周) | 任务 | 依赖 | 状态 | |------|------|------| | Panel 类独立化 | - | ✅ 完成 | | 引入事件总线 | - | ✅ 完成 | | EditorContext 接口定义 | Panel 独立化 | ✅ 完成 | | SelectionManager 改造 | 事件总线 | ✅ 完成 | | EditorLayer 重构 | 上述全部 | ✅ 完成 | **已完成的文件**: - `editor/src/panels/Panel.h/cpp` - 独立的 Panel 基类 - `editor/src/Core/EventBus.h` - 类型安全事件总线 - `editor/src/Core/EditorEvents.h` - 编辑器事件类型定义 - `editor/src/Core/ISelectionManager.h` - 选择管理器接口 - `editor/src/Core/SelectionManagerImpl.h` - 选择管理器实现 - `editor/src/Core/IEditorContext.h` - 编辑器上下文接口 - `editor/src/Core/EditorContextImpl.h` - 编辑器上下文实现 ### 阶段二:核心功能(第 3-4 周) | 任务 | 依赖 | 状态 | |------|------|------| | Undo/Redo 系统 | 事件总线 | TODO | | Command 基类 | - | TODO | | 常用 Command 实现 | Undo/Redo 系统 | TODO | | 场景序列化 | Command 基类 | TODO | | SceneManager 重构 | 事件总线、Command | TODO | ### 阶段三:Inspector 改进(第 5-6 周) | 任务 | 依赖 | 状态 | |------|------|------| | ComponentEditor 接口 | 阶段一完成 | TODO | | TransformComponentEditor | ComponentEditor 接口 | TODO | | MeshRendererComponentEditor | AssetHandle 系统 | TODO | | 动态添加组件 UI | ComponentEditor 接口 | TODO | ### 阶段四:SceneView 实现(第 7-8 周) | 任务 | 依赖 | 状态 | |------|------|------| | CameraController | - | TODO | | GizmosRenderer | CameraController | TODO | | Selection Outline | GizmosRenderer | TODO | | Grid Renderer | - | TODO | ### 阶段五:Play/Edit 模式(第 9-10 周) | 任务 | 依赖 | 状态 | |------|------|------| | EditorStateMachine | 阶段一完成 | TODO | | 场景状态保存/恢复 | 序列化 | TODO | | GameView 集成 | StateMachine | TODO | | 工具栏 UI | GizmosRenderer | TODO | --- ## 五、注意事项 ### 5.1 向后兼容 - 保持 `GameObject`、`Component` 等核心类接口不变 - 新增接口使用 `virtual` 或默认实现 - 序列化格式预留 `version` 字段 ### 5.2 性能考虑 - Undo/Redo 栈限制最大容量 - 事件总线使用 `std::function` 的 `std::any` 存储避免类型擦除开销 - Inspector 使用 `std::unordered_map` 加速组件编辑器查找 ### 5.3 测试计划 - 单元测试:Command、Serializer、EventBus - 集成测试:Undo/Redo 完整流程 - UI 测试:手动测试为主 --- ## 六、代码规范 ### 6.1 命名规范 - Editor 相关类放在 `XCEngine::Editor` 命名空间 - 接口类前缀 `I`(如 `ISelectionManager`) - Editor 内部实现后缀 `Impl`(如 `SelectionManagerImpl`) ### 6.2 文件组织 ``` editor/src/ ├── Core/ │ ├── EditorContext.h/cpp │ ├── EventBus.h/cpp │ └── UndoRedo.h/cpp ├── Commands/ │ ├── Command.h │ ├── CreateEntityCommand.h/cpp │ ├── DeleteEntityCommand.h/cpp │ └── TransformCommand.h/cpp ├── Panels/ │ ├── Panel.h # 基础类 │ ├── HierarchyPanel.h/cpp │ ├── InspectorPanel.h/cpp │ └── ... └── UI/ ├── Gizmos.h/cpp └── CameraController.h/cpp ``` ### 6.3 禁止事项 - ❌ 禁止在 Editor 代码中使用 `static` 单例模式 - ❌ 禁止直接持有 `GameObject*` 裸指针 - ❌ 禁止在 Release 版本保留 `Debug::Logger` 调用 - ❌ 禁止硬编码任何路径