Files
XCEngine/docs/plan/UI-Editor-GameObject缺口分析.md

22 KiB
Raw Blame History

UI-Editor GameObject 缺口分析

基于XCEngine渲染引擎架构设计.md
目标:识别 UI 编辑器 GameObject.h 相对于 Engine 架构设计文档的缺失功能
日期2026-03-20


架构参考

XCEngine 组件系统参考 Unity 传统架构 (GameObject-Component Pattern)

  • GameObject场景中的实体UI Editor 中称 Entity
  • Component:挂载到 GameObject 的功能模块(变换、渲染器等)
  • TransformComponent:每个 GameObject 都有的变换组件,管理位置/旋转/缩放
  • Scene/SceneManager:场景管理和场景切换

Engine 模块现状

模块 状态 UI Editor 对齐情况
Core (Event, Types) 已实现 UI 编辑器已复用 XCEngine::Core::Event<T>
Debug (Logger, LogLevel, LogEntry) 已实现 UI 编辑器已复用 XCEngine::Debug::LogLevel
Math (Vector3, Quaternion, Matrix4x4, Transform, Color) 已实现 可直接复用 Engine Math 类型
Memory 已实现
Threading 已实现
Containers 已实现
RHI / D3D12 已实现 UI 编辑器自行实现(与 Engine 技术栈一致)
Resources 已实现
Components (GameObject, Component, System) 缺失 UI 编辑器自行实现,待 Engine 实现后迁移
Scene (Scene, SceneManager, SceneLoader, SceneSerializer) 缺失 UI 编辑器自行实现,待 Engine 实现后迁移

一、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() XCEngine::Math::Vector3 GetPosition() const 缺失 获取世界坐标
SetPosition() void SetPosition(const XCEngine::Math::Vector3& position) 缺失 设置世界坐标
GetRotation() XCEngine::Math::Quaternion GetRotation() const 缺失 获取世界旋转
SetRotation() void SetRotation(const XCEngine::Math::Quaternion& rotation) 缺失 设置世界旋转
GetScale() XCEngine::Math::Vector3 GetScale() const 缺失 获取世界缩放
SetScale() void SetScale(const XCEngine::Math::Vector3& scale) 缺失 设置世界缩放

2.2 方向向量

架构设计接口 函数签名 状态 说明
GetForward() XCEngine::Math::Vector3 GetForward() const 缺失 获取前向向量
GetRight() XCEngine::Math::Vector3 GetRight() const 缺失 获取右向量
GetUp() XCEngine::Math::Vector3 GetUp() const 缺失 获取上向量

2.3 矩阵变换

架构设计接口 函数签名 状态 说明
GetLocalToWorldMatrix() const XCEngine::Math::Matrix4x4& GetLocalToWorldMatrix() const 缺失 本地到世界矩阵(含缓存)
GetWorldToLocalMatrix() XCEngine::Math::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 XCEngine::Math::Vector3& target) 缺失 朝向目标点
LookAt(target, up) void LookAt(const XCEngine::Math::Vector3& target, const XCEngine::Math::Vector3& up) 缺失 朝向目标点(指定上向量)
Rotate(eulers) void Rotate(const XCEngine::Math::Vector3& eulers) 缺失 欧拉角旋转
Rotate(axis, angle) void Rotate(const XCEngine::Math::Vector3& axis, float angle) 缺失 轴角旋转
Translate(translation) void Translate(const XCEngine::Math::Vector3& translation) 缺失 平移(世界空间)
Translate(translation, relativeTo) void Translate(const XCEngine::Math::Vector3& translation, Space relativeTo) 缺失 平移(指定空间)

2.6 点/方向变换

架构设计接口 函数签名 状态 说明
TransformPoint() XCEngine::Math::Vector3 TransformPoint(const XCEngine::Math::Vector3& point) const 缺失 变换点(含平移旋转)
InverseTransformPoint() XCEngine::Math::Vector3 InverseTransformPoint(const XCEngine::Math::Vector3& point) const 缺失 逆变换点
TransformDirection() XCEngine::Math::Vector3 TransformDirection(const XCEngine::Math::Vector3& direction) const 缺失 变换方向(仅旋转)
InverseTransformDirection() XCEngine::Math::Vector3 InverseTransformDirection(const XCEngine::Math::Vector3& direction) const 缺失 逆变换方向

2.7 脏标记与缓存

架构设计接口 函数签名 状态 说明
SetDirty() void SetDirty() ⚠️ 局部 UI Editor 只有简单 flag缺少完整缓存机制
缓存成员 mutable XCEngine::Math::Matrix4x4 m_localToWorldMatrix 缺失 矩阵缓存
更新方法 void UpdateWorldTransform() const 缺失 缓存失效时重新计算

当前 UI Editor 实现

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};       // 仅有本地缩放
    // 缺少世界空间方法、矩阵缓存、父子指针等
};

架构设计要求(应使用 Engine Math 类型):

class TransformComponent : public Component {
public:
    // 使用 Engine Math 类型
    XCEngine::Math::Vector3 GetLocalPosition() const { return m_localPosition; }
    void SetLocalPosition(const XCEngine::Math::Vector3& pos) { m_localPosition = pos; SetDirty(); }
    
    XCEngine::Math::Quaternion GetLocalRotation() const { return m_localRotation; }
    void SetLocalRotation(const XCEngine::Math::Quaternion& rot) { m_localRotation = rot; SetDirty(); }
    
    XCEngine::Math::Vector3 GetLocalScale() const { return m_localScale; }
    void SetLocalScale(const XCEngine::Math::Vector3& sc) { m_localScale = sc; SetDirty(); }

private:
    XCEngine::Math::Vector3 m_localPosition = XCEngine::Math::Vector3::Zero();
    XCEngine::Math::Quaternion m_localRotation = XCEngine::Math::Quaternion::Identity();
    XCEngine::Math::Vector3 m_localScale = XCEngine::Math::Vector3::One();
    
    TransformComponent* m_parent = nullptr;
    std::vector<TransformComponent*> m_children;
    
    mutable XCEngine::Math::Matrix4x4 m_localToWorldMatrix;
    mutable XCEngine::Math::Matrix4x4 m_worldToLocalMatrix;
    mutable XCEngine::Math::Vector3 m_worldPosition;
    mutable XCEngine::Math::Quaternion m_worldRotation;
    mutable XCEngine::Math::Vector3 m_worldScale;
    mutable bool m_dirty = true;
    
    void UpdateWorldTransform() const;
};

三、GameObject缺口

3.1 基础方法

架构设计接口 函数签名 状态 说明
GetTransform() TransformComponent& GetTransform() 缺失 获取变换组件引用
GetScene() Scene* GetScene() const 缺失 获取所属场景

3.2 组件查找

架构设计接口 函数签名 状态 说明
GetComponentInChildren<T>() T* GetComponentInChildren() const 缺失 在子实体中查找组件
GetComponentsInChildren<T>() std::vector<T*> GetComponentsInChildren() const 缺失 获取所有子实体中的组件
GetComponentInParent<T>() T* GetComponentInParent() const 缺失 在父实体中查找组件

3.3 父子层级

架构设计接口 函数签名 状态 说明
SetParent(parent) void SetParent(Entity* parent) 缺失 2参数版本含 worldPositionStays
GetChildren() const std::vector<Entity*>& GetChildren() const 缺失 获取子实体列表
GetChild() Entity* 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 Entity* Find(const String& name) 缺失 按名称查找实体
FindObjectsOfType() static std::vector<Entity*> FindObjectsOfType() 缺失 查找所有实体
FindGameObjectsWithTag() static std::vector<Entity*> 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) Entity* CreateGameObject(const String& name, Entity* parent) 缺失 带父实体创建
GetRootGameObjects() std::vector<Entity*> GetRootGameObjects() const 缺失 获取根实体列表
Find() Entity* Find(const String& name) const 缺失 查找实体
FindGameObjectWithTag() Entity* FindGameObjectWithTag(const String& tag) const 缺失 按标签查找
FindObjectsOfType<T>() std::vector<T*> FindObjectsOfType() const 缺失 模板查找
FindObjectOfType<T>() 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<void(Scene*)> 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<Scene*> GetAllScenes() const 缺失 获取所有场景
OnSceneLoaded Event<Scene*> ⚠️ 差异 UI Editor 是 OnSceneChanged
OnSceneUnloaded Event<Scene*> 缺失 场景卸载事件
OnActiveSceneChanged Event<Scene*> 缺失 激活场景变更事件

4.3 GameObjectBuilder 类

架构设计接口 函数签名 状态 说明
完整类 class GameObjectBuilder 缺失 实体创建辅助类

五、实现优先级

P0 - 核心缺失(必须实现)

模块 原因 涉及文件
TransformComponent 世界空间方法 Editor 变换编辑基础 GameObject.h
Entity GetTransform() Inspector 面板需要 GameObject.h
Component transform() 组件访问变换 GameObject.h

依赖Engine Math 模块 已实现,可直接使用 XCEngine::Math::Vector3 / Quaternion / Matrix4x4

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<unique_ptr<Component>> vector<unique_ptr<Component>> 已对齐
变换类型 float[3] 数组 XCEngine::Math::Vector3 / Quaternion ⚠️ 应改用 Engine Math
父子关系 EntityID (uint64) Entity* 指针 ⚠️ UI 用 IDEngine 用指针
场景管理 全局单例 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 功能相似,命名不同

6.3 类型复用情况

Engine 类型 UI Editor 现状 建议
XCEngine::Math::Vector3 UI Editor 用 float[3] 直接复用
XCEngine::Math::Quaternion UI Editor 用 float[3] (欧拉角) 直接复用,但欧拉角存储可保留
XCEngine::Math::Matrix4x4 直接复用
XCEngine::Core::Event<T> 已复用 保持
XCEngine::Debug::LogLevel 已复用 保持

七、依赖关系分析

实现优先级 - 依赖链:

P0: TransformComponent 世界空间
    │
    ├── 需要: XCEngine::Math::Vector3 ✅ 已实现
    ├── 需要: XCEngine::Math::Quaternion ✅ 已实现
    ├── 需要: XCEngine::Math::Matrix4x4 ✅ 已实现
    └── 影响: Entity::GetTransform()

P0: Component::transform()
    │
    └── 依赖: Entity::GetTransform()

P1: TransformComponent 父子指针
    │
    ├── 需要: TransformComponent* parent
    ├── 需要: vector<TransformComponent*> children
    └── 影响: Entity 父子操作

P1: Entity 激活状态
    │
    ├── 需要: active 成员
    └── 影响: IsActiveInHierarchy()

P1: Scene 多场景
    │
    ├── 需要: Scene 类
    ├── 需要: Scene::CreateGameObject()
    └── 影响: SceneManager 重构

八、与 Unity 架构的对照

Unity 传统架构 (GameObject-Component)

Scene
  └── GameObject ("MyEntity")
        ├── Transform
        ├── MeshRenderer
        └── (其他组件...)

GameObject.GetComponent<T>()      →  Entity.GetComponent<T>()
GameObject.transform              →  Entity.GetTransform()
GameObject.SetActive(bool)        →  缺失
GameObject.Find("name")           →  缺失
Scene.GetRootGameObjects()         →  缺失
SceneManager.GetActiveScene()      →  缺失

UI Editor 当前实现

SceneManager (全局单例)
  └── m_entities (unordered_map<EntityID, Entity>)
        └── Entity ("MyEntity")
              ├── id, name, parent, children
              ├── components (vector<unique_ptr<Component>>)
              └── selected

Entity.AddComponent<T>()          →  ✅ 已实现
Entity.GetComponent<T>()          →  ✅ 已实现
Entity.GetTransform()              →  ❌ 缺失
TransformComponent 世界空间方法    →  ❌ 缺失

九、附录:当前 GameObject.h 完整内容

// ui_editor/src/Core/GameObject.h 当前实现

#pragma once

#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>
#include <cstdint>

#include <XCEngine/Core/Event.h>

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<EntityID> children;
    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;
    }
};

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;
};

} // namespace UI

文档结束