From 761552273b03a5f9c8354a6e673572e0bf3d9b09 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Fri, 20 Mar 2026 19:06:11 +0800 Subject: [PATCH] Docs: Add UI-Editor design documents --- docs/plan/UI-Editor-GameObject缺口分析.md | 461 ++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 docs/plan/UI-Editor-GameObject缺口分析.md diff --git a/docs/plan/UI-Editor-GameObject缺口分析.md b/docs/plan/UI-Editor-GameObject缺口分析.md new file mode 100644 index 00000000..17d760d9 --- /dev/null +++ b/docs/plan/UI-Editor-GameObject缺口分析.md @@ -0,0 +1,461 @@ +# UI-Editor GameObject 缺口分析 + +> **基于**:XCEngine渲染引擎架构设计.md +> **目标**:识别 UI 编辑器 GameObject.h 相对于 Engine 架构设计文档的缺失功能 +> **日期**:2026-03-20 + +--- + +## 一、Component 基类缺口 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `transform()` | `TransformComponent& transform() const` | ❌ 缺失 | 返回所在实体的 TransformComponent 引用 | +| `GetScene()` | `Scene* GetScene() const` | ❌ 缺失 | 返回所属 Scene 指针 | +| `FixedUpdate()` | `virtual void FixedUpdate()` | ❌ 缺失 | 物理更新(每固定帧) | +| `LateUpdate()` | `virtual void LateUpdate(float deltaTime)` | ❌ 缺失 | 晚于 Update 执行 | +| `OnEnable()` | `virtual void OnEnable()` | ❌ 缺失 | 组件启用时调用 | +| `OnDisable()` | `virtual void OnDisable()` | ❌ 缺失 | 组件禁用时调用 | +| `friend class` | `friend class GameObject` | ⚠️ 差异 | UI Editor 是 `friend class Entity` | + +**补充说明**: +- UI Editor 的 `Component` 需要增加 `TransformComponent*` 获取方法以支持 Inspector 面板的变换编辑 +- Engine 的 `m_gameObject` 在 UI Editor 中对应 `m_entity` + +--- + +## 二、TransformComponent 缺口 + +### 2.1 World 空间方法 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetPosition()` | `Vector3 GetPosition() const` | ❌ 缺失 | 获取世界坐标 | +| `SetPosition()` | `void SetPosition(const Vector3& position)` | ❌ 缺失 | 设置世界坐标 | +| `GetRotation()` | `Quaternion GetRotation() const` | ❌ 缺失 | 获取世界旋转 | +| `SetRotation()` | `void SetRotation(const Quaternion& rotation)` | ❌ 缺失 | 设置世界旋转 | +| `GetScale()` | `Vector3 GetScale() const` | ❌ 缺失 | 获取世界缩放 | +| `SetScale()` | `void SetScale(const Vector3& scale)` | ❌ 缺失 | 设置世界缩放 | + +### 2.2 方向向量 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetForward()` | `Vector3 GetForward() const` | ❌ 缺失 | 获取前向向量 | +| `GetRight()` | `Vector3 GetRight() const` | ❌ 缺失 | 获取右向量 | +| `GetUp()` | `Vector3 GetUp() const` | ❌ 缺失 | 获取上向量 | + +### 2.3 矩阵变换 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetLocalToWorldMatrix()` | `const Matrix4x4& GetLocalToWorldMatrix() const` | ❌ 缺失 | 本地到世界矩阵(含缓存) | +| `GetWorldToLocalMatrix()` | `Matrix4x4 GetWorldToLocalMatrix() const` | ❌ 缺失 | 世界到本地矩阵 | + +### 2.4 父子层级 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetParent()` | `TransformComponent* GetParent() const` | ❌ 缺失 | 获取父变换 | +| `SetParent()` | `void SetParent(TransformComponent* parent, bool worldPositionStays = true)` | ❌ 缺失 | 设置父变换 | +| `GetChild()` | `TransformComponent* GetChild(int index) const` | ❌ 缺失 | 按索引获取子变换 | +| `Find()` | `TransformComponent* Find(const String& name) const` | ❌ 缺失 | 按名称查找子变换 | +| `DetachChildren()` | `void DetachChildren()` | ❌ 缺失 | 断开所有子节点 | +| `SetAsFirstSibling()` | `void SetAsFirstSibling()` | ❌ 缺失 | 设为第一个同级 | +| `SetAsLastSibling()` | `void SetAsLastSibling()` | ❌ 缺失 | 设为最后一个同级 | +| `GetSiblingIndex()` | `int GetSiblingIndex() const` | ❌ 缺失 | 获取同级索引 | +| `SetSiblingIndex()` | `void SetSiblingIndex(int index)` | ❌ 缺失 | 设置同级索引 | + +### 2.5 变换操作 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `LookAt(target)` | `void LookAt(const Vector3& target)` | ❌ 缺失 | 朝向目标点 | +| `LookAt(target, up)` | `void LookAt(const Vector3& target, const Vector3& up)` | ❌ 缺失 | 朝向目标点(指定上向量) | +| `Rotate(eulers)` | `void Rotate(const Vector3& eulers)` | ❌ 缺失 | 欧拉角旋转 | +| `Rotate(axis, angle)` | `void Rotate(const Vector3& axis, float angle)` | ❌ 缺失 | 轴角旋转 | +| `Translate(translation)` | `void Translate(const Vector3& translation)` | ❌ 缺失 | 平移(世界空间) | +| `Translate(translation, relativeTo)` | `void Translate(const Vector3& translation, Space relativeTo)` | ❌ 缺失 | 平移(指定空间) | + +### 2.6 点/方向变换 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `TransformPoint()` | `Vector3 TransformPoint(const Vector3& point) const` | ❌ 缺失 | 变换点(含平移旋转) | +| `InverseTransformPoint()` | `Vector3 InverseTransformPoint(const Vector3& point) const` | ❌ 缺失 | 逆变换点 | +| `TransformDirection()` | `Vector3 TransformDirection(const Vector3& direction) const` | ❌ 缺失 | 变换方向(仅旋转) | +| `InverseTransformDirection()` | `Vector3 InverseTransformDirection(const Vector3& direction) const` | ❌ 缺失 | 逆变换方向 | + +### 2.7 脏标记与缓存 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `SetDirty()` | `void SetDirty()` | ⚠️ 局部 | UI Editor 只有简单 flag,缺少完整缓存机制 | +| 缓存成员 | `mutable Matrix4x4 m_localToWorldMatrix` 等 | ❌ 缺失 | 矩阵缓存 | +| 更新方法 | `void UpdateWorldTransform() const` | ❌ 缺失 | 缓存失效时重新计算 | + +**当前 UI Editor 实现**: +```cpp +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}; // 仅有本地缩放 + // 缺少世界空间方法、矩阵缓存、父子指针等 +}; +``` + +**架构设计要求**: +```cpp +class TransformComponent : public Component { +private: + Vector3 m_localPosition = Vector3::Zero(); + Quaternion m_localRotation = Quaternion::Identity(); + Vector3 m_localScale = Vector3::One(); + + TransformComponent* m_parent = nullptr; + std::vector m_children; + + mutable Matrix4x4 m_localToWorldMatrix; + mutable Matrix4x4 m_worldToLocalMatrix; + mutable Vector3 m_worldPosition; + mutable Quaternion m_worldRotation; + mutable Vector3 m_worldScale; + mutable bool m_dirty = true; + + void UpdateWorldTransform() const; +}; +``` + +--- + +## 三、Entity(GameObject)缺口 + +### 3.1 基础方法 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetTransform()` | `TransformComponent& GetTransform()` | ❌ 缺失 | 获取变换组件引用 | +| `GetScene()` | `Scene* GetScene() const` | ❌ 缺失 | 获取所属场景 | + +### 3.2 组件查找 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetComponentInChildren()` | `T* GetComponentInChildren() const` | ❌ 缺失 | 在子实体中查找组件 | +| `GetComponentsInChildren()` | `std::vector GetComponentsInChildren() const` | ❌ 缺失 | 获取所有子实体中的组件 | +| `GetComponentInParent()` | `T* GetComponentInParent() const` | ❌ 缺失 | 在父实体中查找组件 | + +### 3.3 父子层级 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `SetParent(parent)` | `void SetParent(GameObject* parent)` | ❌ 缺失 | 2参数版本(含 worldPositionStays) | +| `GetChildren()` | `const std::vector& GetChildren() const` | ❌ 缺失 | 获取子实体列表 | +| `GetChild()` | `GameObject* GetChild(int index) const` | ❌ 缺失 | 按索引获取子实体 | + +### 3.4 激活状态 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `active` 成员 | `bool active = true` | ❌ 缺失 | 实体激活状态 | +| `SetActive()` | `void SetActive(bool active)` | ❌ 缺失 | 设置激活状态 | +| `IsActive()` | `bool IsActive() const` | ❌ 缺失 | 检查激活状态 | +| `IsActiveInHierarchy()` | `bool IsActiveInHierarchy() const` | ❌ 缺失 | 检查层级中的激活状态 | + +### 3.5 静态查找 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `Find()` | `static GameObject* Find(const String& name)` | ❌ 缺失 | 按名称查找实体 | +| `FindObjectsOfType()` | `static std::vector FindObjectsOfType()` | ❌ 缺失 | 查找所有实体 | +| `FindGameObjectsWithTag()` | `static std::vector FindGameObjectsWithTag(const String& tag)` | ❌ 缺失 | 按标签查找 | + +### 3.6 销毁 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `Destroy()` | `void Destroy()` | ❌ 缺失 | 实例方法销毁(通过 Scene) | + +--- + +## 四、Scene / SceneManager 缺口 + +### 4.1 Scene 类 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `GetName()` | `const String& GetName() const` | ❌ 缺失 | 获取场景名称 | +| `SetName()` | `void SetName(const String& name)` | ❌ 缺失 | 设置场景名称 | +| `CreateGameObject(name, parent)` | `GameObject* CreateGameObject(const String& name, GameObject* parent)` | ❌ 缺失 | 带父实体创建 | +| `GetRootGameObjects()` | `std::vector GetRootGameObjects() const` | ❌ 缺失 | 获取根实体列表 | +| `Find()` | `GameObject* Find(const String& name) const` | ❌ 缺失 | 查找实体 | +| `FindGameObjectWithTag()` | `GameObject* FindGameObjectWithTag(const String& tag) const` | ❌ 缺失 | 按标签查找 | +| `FindObjectsOfType()` | `std::vector FindObjectsOfType() const` | ❌ 缺失 | 模板查找 | +| `FindObjectOfType()` | `T* FindObjectOfType() const` | ❌ 缺失 | 查找单个 | +| `IsActive()` | `bool IsActive() const` | ❌ 缺失 | 场景激活状态 | +| `SetActive()` | `void SetActive(bool active)` | ❌ 缺失 | 设置激活状态 | +| `Load()` | `void Load(const String& filePath)` | ❌ 缺失 | 加载场景 | +| `Save()` | `void Save(const String& filePath)` | ❌ 缺失 | 保存场景 | +| `Update()` | `void Update(float deltaTime)` | ❌ 缺失 | 场景更新 | +| `FixedUpdate()` | `void FixedUpdate(float fixedDeltaTime)` | ❌ 缺失 | 物理更新 | +| `LateUpdate()` | `void LateUpdate(float deltaTime)` | ❌ 缺失 | 晚更新 | + +**当前 UI Editor 缺失 Scene 概念**,所有实体都在 SceneManager 全局管理。 + +### 4.2 SceneManager 类 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| `CreateScene()` | `Scene* CreateScene(const String& name)` | ❌ 缺失 | 创建场景 | +| `LoadScene()` | `void LoadScene(const String& filePath)` | ❌ 缺失 | 同步加载 | +| `LoadSceneAsync()` | `void LoadSceneAsync(const String& filePath, std::function callback)` | ❌ 缺失 | 异步加载 | +| `UnloadScene(scene)` | `void UnloadScene(Scene* scene)` | ❌ 缺失 | 卸载场景 | +| `UnloadScene(name)` | `void UnloadScene(const String& sceneName)` | ❌ 缺失 | 按名称卸载 | +| `SetActiveScene(scene)` | `void SetActiveScene(Scene* scene)` | ❌ 缺失 | 设置激活场景 | +| `SetActiveScene(name)` | `void SetActiveScene(const String& sceneName)` | ❌ 缺失 | 按名称设置 | +| `GetActiveScene()` | `Scene* GetActiveScene() const` | ❌ 缺失 | 获取激活场景 | +| `GetScene(name)` | `Scene* GetScene(const String& name) const` | ❌ 缺失 | 按名称获取场景 | +| `GetAllScenes()` | `std::vector GetAllScenes() const` | ❌ 缺失 | 获取所有场景 | +| `OnSceneLoaded` | `Event` | ⚠️ 差异 | UI Editor 是 `OnSceneChanged` | +| `OnSceneUnloaded` | `Event` | ❌ 缺失 | 场景卸载事件 | +| `OnActiveSceneChanged` | `Event` | ❌ 缺失 | 激活场景变更事件 | + +### 4.3 GameObjectBuilder 类 + +| 架构设计接口 | 函数签名 | 状态 | 说明 | +|------------|---------|------|------| +| 完整类 | `class GameObjectBuilder` | ❌ 缺失 | 实体创建辅助类 | + +--- + +## 五、实现优先级 + +### P0 - 核心缺失(必须实现) + +| 模块 | 原因 | 涉及文件 | +|-----|------|---------| +| TransformComponent 世界空间方法 | Editor 变换编辑基础 | GameObject.h | +| Entity `GetTransform()` | Inspector 面板需要 | GameObject.h | +| Component `transform()` | 组件访问变换 | GameObject.h | + +### P1 - 功能完整(应该实现) + +| 模块 | 原因 | 涉及文件 | +|-----|------|---------| +| TransformComponent 矩阵缓存 | 性能优化 | GameObject.h | +| TransformComponent 父子指针 | 层级操作 | GameObject.h | +| Entity 激活状态 | 运行时状态 | GameObject.h | +| Entity 父子层级操作 | 层级编辑 | GameObject.h | +| Scene 概念 | 多场景支持 | SceneManager.h | +| SceneManager 多场景管理 | 场景隔离 | SceneManager.h | + +### P2 - 高级功能(可选实现) + +| 模块 | 原因 | 涉及文件 | +|-----|------|---------| +| Scene 序列化/反序列化 | 持久化 | SceneManager.h | +| TransformComponent 点/方向变换 | Gizmos 操作 | GameObject.h | +| SceneManager 异步加载 | 体验优化 | SceneManager.h | +| Entity 静态查找 | Editor 操作 | GameObject.h | + +--- + +## 六、数据结构对齐表 + +### 6.1 当前 UI Editor vs 架构设计 + +| 项目 | UI Editor 当前 | 架构设计 | 对齐建议 | +|-----|--------------|---------|---------| +| 实体内组件存储 | `vector>` | `vector>` | ✅ 已对齐 | +| 变换存储 | `float[3]` 数组 | `Vector3` / `Quaternion` | ⚠️ UI Editor 自行实现,接口对齐即可 | +| 父子关系 | `EntityID` (uint64) | `GameObject*` 指针 | ⚠️ UI 用 ID,Engine 用指针 | +| 场景管理 | 全局单例 SceneManager | 多 Scene + SceneManager | ❌ 需要重构 | + +### 6.2 命名差异 + +| UI Editor | Engine 架构设计 | 说明 | +|-----------|---------------|------| +| `Entity` | `GameObject` | UI Editor 使用 Entity 避免与 std 冲突 | +| `EntityID` | `uint64_t` | UI Editor 自定义类型别名 | +| `INVALID_ENTITY_ID` | N/A | UI Editor 自定义常量 | +| `ComponentRegistry` | `ComponentTypeRegistry` | 功能相似,命名不同 | + +--- + +## 七、依赖关系分析 + +``` +实现优先级 - 依赖链: + +P0: TransformComponent 世界空间 + │ + ├── 需要: Vector3/Quaternion 数学类型 + ├── 需要: 矩阵计算方法 + └── 影响: Entity::GetTransform() + +P0: Component::transform() + │ + └── 依赖: Entity::GetTransform() + +P1: TransformComponent 父子指针 + │ + ├── 需要: TransformComponent* parent + ├── 需要: vector children + └── 影响: Entity 父子操作 + +P1: Entity 激活状态 + │ + ├── 需要: active 成员 + └── 影响: IsActiveInHierarchy() + +P1: Scene 多场景 + │ + ├── 需要: Scene 类 + ├── 需要: Scene::CreateGameObject() + └── 影响: SceneManager 重构 +``` + +--- + +## 八、附录:当前 GameObject.h 完整内容 + +```cpp +// ui_editor/src/Core/GameObject.h 当前实现 + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace UI { + +using EntityID = uint64_t; +constexpr EntityID INVALID_ENTITY_ID = 0; + +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; +}; + +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"; } +}; + +class MeshRendererComponent : public Component { +public: + std::string materialName = "Default-Material"; + std::string meshName = ""; + + std::string GetName() const override { return "Mesh Renderer"; } +}; + +class Entity { +public: + EntityID id = INVALID_ENTITY_ID; + std::string name; + EntityID parent = INVALID_ENTITY_ID; + std::vector children; + std::vector> components; + bool selected = false; + + template + T* AddComponent(Args&&... args) { + auto comp = std::make_unique(std::forward(args)...); + comp->m_entity = this; + T* ptr = comp.get(); + components.push_back(std::move(comp)); + return ptr; + } + + template + T* GetComponent() { + for (auto& comp : components) { + if (auto casted = dynamic_cast(comp.get())) { + return casted; + } + } + return nullptr; + } + + template + std::vector GetComponents() { + std::vector result; + for (auto& comp : components) { + if (auto casted = dynamic_cast(comp.get())) { + result.push_back(casted); + } + } + return result; + } +}; + +using ComponentInspectorFn = std::function; + +struct ComponentInspectorInfo { + std::string name; + ComponentInspectorFn renderFn; +}; + +class ComponentRegistry { +public: + static ComponentRegistry& Get() { + static ComponentRegistry instance; + return instance; + } + + template + void RegisterComponent(const std::string& name, ComponentInspectorFn inspectorFn) { + m_inspectors[name] = {name, inspectorFn}; + m_factories[name] = []() -> std::unique_ptr { + return std::make_unique(); + }; + } + + 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 m_inspectors; + std::unordered_map()>> m_factories; +}; + +} // namespace UI +``` + +--- + +**文档结束**