Files
XCEngine/docs/used/Editor重构计划.md

591 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<IEditorContext> context) { m_context = context; }
private:
std::shared_ptr<IEditorContext> m_context;
};
```
#### 3.1.3 引入事件总线
**新增 `EditorEventBus`**
```cpp
class EditorEventBus {
public:
template<typename T>
void Subscribe(std::function<void(const T&)> handler);
template<typename T>
void Unsubscribe(uint64_t id);
template<typename T>
void Publish(const T& event);
private:
std::unordered_map<size_t, std::vector<std::function<void(void*)>>> m_handlers;
std::unordered_map<size_t, uint64_t> m_nextId;
};
```
**定义事件类型**
```cpp
struct SelectionChangedEvent {
std::vector<GameObjectID> selectedObjects;
};
struct EntityCreatedEvent {
GameObjectID entityId;
};
struct EntityDestroyedEvent {
GameObjectID entityId;
};
```
#### 3.1.4 GameObject 生命周期管理
**现状**
```cpp
::XCEngine::Components::GameObject* m_selectedGameObject = nullptr; // ❌ 裸指针
```
**重构**
```cpp
using GameObjectHandle = ResourceHandle<GameObject>;
struct SelectionState {
std::vector<GameObjectHandle> 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<GameObjectHandle> 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<ICommand> 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<std::unique_ptr<ICommand>> 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<TransformComponent*>(component) != nullptr;
}
void Render(Component* component) override;
};
class InspectorPanel {
public:
void RegisterComponentEditor(std::unique_ptr<IComponentEditor> editor);
void RenderGameObject(GameObject* gameObject);
private:
std::vector<std::unique_ptr<IComponentEditor>> m_editors;
std::unique_ptr<IComponentEditor> GetEditorFor(Component* component);
};
```
**注册默认编辑器**
```cpp
void InspectorPanel::Initialize() {
RegisterComponentEditor(std::make_unique<TransformComponentEditor>());
// 后续添加更多编辑器
}
```
#### 3.2.4 资源引用系统
**AssetHandle**
```cpp
template<typename T>
class AssetHandle {
public:
AssetHandle() = default;
explicit AssetHandle(AssetID id, std::shared_ptr<T> 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<T> m_asset;
};
class MeshRendererComponent {
public:
AssetHandle<Mesh> GetMesh() const { return m_mesh; }
void SetMesh(AssetHandle<Mesh> mesh) { m_mesh = mesh; }
private:
AssetHandle<Mesh> m_mesh;
AssetHandle<Material> 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<Axis> 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/SelectionManager.h` - 选择管理器实现
- `editor/src/Core/IEditorContext.h` - 编辑器上下文接口
- `editor/src/Core/EditorContext.h` - 编辑器上下文实现
- `editor/src/Core/EditorConsoleSink.h/cpp` - Editor 专用日志 Sink
**2026-03-25 更新**
- `editor/src/panels/HierarchyPanel.h/cpp` - 已迁移至 IEditorContext
- `editor/src/panels/InspectorPanel.h/cpp` - 已迁移至 IEditorContext + EventBus
- 移除了所有 Panel 中的 `SelectionManager::Get()``EditorSceneManager::Get()` 单例调用
- SceneManager::RenameEntity 实现已添加
- **日志系统统一**:删除了独立的 LogSystem 单例Editor 和 Engine 共用 Debug::Logger
- ConsolePanel 改用 EditorConsoleSink 从 Logger 读取日志
- 删除了 `editor/src/Managers/LogSystem.h/cpp``editor/src/Core/LogEntry.h`
- **命名规范修复**SelectionManagerImpl → SelectionManagerEditorContextImpl → EditorContext
- 删除了未使用的 SceneManagerImpl 和 ISceneManager
- **ProjectManager 单例移除**:创建了 IProjectManager 接口ProjectManager 实现该接口EditorContext 拥有实例
- **ISceneManager 接口**:创建了 ISceneManager 接口SceneManager 实现该接口
- **IEditorContext::GetSceneManager() 返回类型**:从 `void*` 改为 `ISceneManager&`
- **HierarchyPanel EventBus 订阅**HierarchyPanel 现在订阅 SelectionChangedEvent
### 阶段二:核心功能(第 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` 调用
- ❌ 禁止硬编码任何路径