Files
XCEngine/docs/api/XCEngine/Components/TransformComponent/TransformComponent.md

160 lines
6.0 KiB
Markdown
Raw Normal View History

2026-03-26 16:45:24 +08:00
# TransformComponent
**命名空间**: `XCEngine::Components`
**类型**: `class`
**头文件**: `XCEngine/Components/TransformComponent.h`
2026-03-27 16:15:00 +08:00
**描述**: `GameObject` 的内建变换组件,负责局部/世界空间变换、层级矩阵计算和常见的空间操作。
## 角色概述
`TransformComponent` 是当前对象树里最基础、也是最特殊的组件。它既继承自 `Component`,又不属于普通“可随意添加和删除”的组件集合:
- 每个 `GameObject` 构造时都会创建一个 `TransformComponent`
- 普通组件通过 `Component::transform()` 获取它。
- 场景层级和空间层级的大部分语义都围绕它展开。
如果把整个 `Components` 模块类比成 Unity 风格对象系统,那么 `TransformComponent` 对应的就是最接近 Unity `Transform` 的那一层基础设施。
## 局部与世界变换
类型内部同时维护:
- 局部数据:`m_localPosition``m_localRotation``m_localScale`
- 派生缓存:`m_localToWorldMatrix``m_worldPosition``m_worldRotation``m_worldScale`
- 脏标记:`m_dirty`
当前实现使用懒更新模式:
- 修改局部位置、旋转或缩放时,调用 `SetDirty()`
- 真正读取世界矩阵、世界位置、世界旋转或世界缩放时,才通过 `UpdateWorldTransform()` 重新计算
这是一种常见的商业引擎做法,优点是多个 setter 可以先累积,再在真正需要世界空间数据时统一计算;代价是层级脏标记传播一定要正确,否则很容易出现缓存过期问题。
## 层级关系
`TransformComponent` 自己维护一套父子变换树:
- `GetParent()`
- `SetParent(TransformComponent*, bool worldPositionStays = true)`
- `GetChild()`
- `GetChildCount()`
- `DetachChildren()`
但要注意,变换树和 `GameObject` 的对象树虽然通常同步,却不是完全同一个概念。
### 推荐做法
当你操作真实场景对象关系时,优先使用 `GameObject::SetParent()`
原因是 `GameObject::SetParent()` 会同时处理:
- `GameObject` 子列表
- 场景根节点列表
- 激活层级变化传播
- 对应 `Transform` 的父子关系
而直接调用 `TransformComponent::SetParent()` 只会改变变换树,不会完整维护场景对象树的其他语义。
## 空间操作
`TransformComponent` 提供了当前最常用的一组空间 API
- 世界/局部位置、旋转、缩放读写
- `GetForward()``GetRight()``GetUp()`
- `LookAt()`
- `Rotate()``Translate()`
- `TransformPoint()` / `InverseTransformPoint()`
- `TransformDirection()` / `InverseTransformDirection()`
从实现看,这些方法都是直接基于 `Quaternion``Matrix4x4` 和当前缓存矩阵完成的轻量封装,没有额外的物理、动画或约束系统参与。
## 查找语义
`Find(const std::string& name)` 的行为容易被误解。按当前实现,它不是“从当前节点的子树开始找”,而是:
1. 通过宿主 `GameObject` 拿到所属 `Scene`
2. 从场景所有 root game objects 开始递归搜索
3. 找到第一个名称匹配的 `GameObject` 后返回其 `Transform`
因此,它更像一个场景级按名称查找的快捷入口,而不是严格的局部子树查询 API。
## 序列化语义
`Serialize()` / `Deserialize()` 当前只处理局部变换:
- `position`
- `rotation`
- `scale`
不会直接写出父子关系,也不会直接写出世界矩阵缓存。世界空间数据会在反序列化后通过 `SetDirty()` 延迟重建。
这和商业引擎常见做法一致:持久化局部值,把世界值当运行时派生结果。
## 线程语义
- 当前实现没有内部加锁。
- `m_dirty`、父子列表和缓存矩阵都按单线程访问模型设计。
- 默认应在主线程或明确受控的场景更新线程上读写。
## 当前实现限制
- `SetDirty()` 会递归标记所有子节点,这是正确方向,但如果层级很深,批量修改会带来明显传播成本。
- `SetSiblingIndex()``SetAsFirstSibling()``SetAsLastSibling()` 当前只修改 `m_siblingIndex` 数值,没有真正重排父节点 `m_children` 顺序。
- `DetachChildren()` 只改 `TransformComponent` 自己的父子指针,不会同步处理 `GameObject` 层级与 `Scene` 根节点列表。
- `Find()` 是场景级名称搜索,不是局部子树搜索。
这些限制非常值得在编辑器或脚本层显式规避。
## 推荐使用方式
1. 日常层级重组优先用 `GameObject::SetParent()`
2.`TransformComponent` 视为内建基础设施,不要尝试把它当普通组件那样增删。
3. 需要保存/加载时只关心局部值,不要手动持久化世界矩阵。
4. 使用 `Find()` 时明确它是场景级名称匹配,不要把它当路径查询接口。
## 相关方法
- [Constructor](Constructor.md)
- [GetLocalPosition](GetLocalPosition.md)
- [SetLocalPosition](SetLocalPosition.md)
- [GetLocalRotation](GetLocalRotation.md)
- [SetLocalRotation](SetLocalRotation.md)
- [GetLocalScale](GetLocalScale.md)
- [SetLocalScale](SetLocalScale.md)
- [GetPosition](GetPosition.md)
- [SetPosition](SetPosition.md)
- [GetRotation](GetRotation.md)
- [SetRotation](SetRotation.md)
- [GetScale](GetScale.md)
- [SetScale](SetScale.md)
- [GetLocalToWorldMatrix](GetLocalToWorldMatrix.md)
- [GetWorldToLocalMatrix](GetWorldToLocalMatrix.md)
- [SetParent](SetParent.md)
- [Find](Find.md)
- [DetachChildren](DetachChildren.md)
- [SetDirty](SetDirty.md)
- [UpdateWorldTransform](UpdateWorldTransform.md)
- [LookAt](LookAt.md)
- [Rotate](Rotate.md)
- [Translate](Translate.md)
- [TransformPoint](TransformPoint.md)
- [InverseTransformPoint](InverseTransformPoint.md)
- [TransformDirection](TransformDirection.md)
- [InverseTransformDirection](InverseTransformDirection.md)
- [Serialize](Serialize.md)
- [Deserialize](Deserialize.md)
## 相关指南
- [GameObject-Component Lifecycle And Serialization](../../../_guides/Components/GameObject-Component-Lifecycle-And-Serialization.md)
2026-03-26 16:45:24 +08:00
## 相关文档
2026-03-27 16:15:00 +08:00
- [当前模块](../Components.md)
- [GameObject](../GameObject/GameObject.md)
- [Component](../Component/Component.md)
- [API 总索引](../../../main.md)