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

103 lines
4.6 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.
# Component
**命名空间**: `XCEngine::Components`
**类型**: `class (abstract base)`
**头文件**: `XCEngine/Components/Component.h`
**描述**: 所有挂载式组件的抽象基类,定义统一的生命周期钩子、归属对象访问和启用状态控制。
## 角色概述
`Component``GameObject` 组合模型里的最小行为单元。它本身不拥有场景对象,也不负责更新循环;真正的驱动者是 `GameObject``Scene``Component` 主要提供三类能力:
- 生命周期钩子:`Awake``Start``Update``FixedUpdate``LateUpdate``OnEnable``OnDisable``OnDestroy`
- 归属关系访问:`GetGameObject()``transform()``GetScene()`
- 运行期开关:`IsEnabled()``SetEnabled()`
这和 Unity 的 `Component`/`Behaviour` 设计思路相近,但当前实现更轻:基类默认几乎全部是空实现,没有调度器、执行顺序系统或线程隔离层。
## 生命周期
`Component` 的生命周期由宿主 `GameObject` 驱动,而不是由组件自身驱动。
- `Awake()``Start()``Update()``FixedUpdate()``LateUpdate()` 只有在 `GameObject`/`Scene` 主动调用时才会发生。
- `SetEnabled()` 会根据“组件启用状态”和“对象是否在层级中激活”共同决定是否触发 `OnEnable()``OnDisable()`
- `OnDestroy()``GameObject::Destroy()``Scene::DestroyGameObject()` 路径触发;基类析构函数本身不补发销毁回调。
按当前实现,直接对一个已经运行中的 `GameObject` 调用 `AddComponent<T>()`,不会自动调用新组件的 `Awake()``Start()``OnEnable()`。如果你的运行时逻辑依赖这些阶段,需要明确安排调用时机。
## 所有权与归属
- `Component` 不直接暴露 public 构造 ownership实例通常由 `GameObject` 持有在 `std::unique_ptr<Component>` 容器中。
- `m_gameObject``GameObject::AddComponent<T>()` 在挂接时回填。
- `GetGameObject()` 仅返回裸指针,不转移所有权。
- `GetScene()` 只是经由宿主对象转发访问场景。
`transform()` 的前提条件比 `GetScene()` 更严格。当前实现直接解引用 `m_gameObject->GetTransform()`,没有空指针保护,因此它只适用于“已经成功挂到某个 `GameObject` 上”的组件。
## 启用状态语义
`SetEnabled(bool)` 的有效状态不是单纯的 `m_enabled`,而是:
`component enabled && gameObject active in hierarchy`
这意味着:
- 对挂在非激活对象上的组件执行 `SetEnabled(true)`,不会立刻触发 `OnEnable()`
- 当对象重新进入激活层级时,`GameObject` 会补发 `OnEnable()`
- 如果启用状态前后“有效可用性”没有变化,`SetEnabled()` 会直接返回,不重复触发回调。
这套行为已被 `tests/Components/test_component.cpp` 覆盖验证。
## 序列化语义
- 基类 `Serialize(std::ostream&)` 默认是 no-op。
- 基类 `Deserialize(std::istream&)` 默认是 no-op。
因此,组件是否能被场景保存/加载,完全取决于具体子类是否覆写这两个函数。文档阅读时不要默认所有组件都可持久化。
## 线程语义
- 当前实现没有内部加锁。
- 文档和源码都没有提供跨线程读写同一组件实例的安全保证。
- 按当前调用关系,生命周期和大多数组件访问应默认视为主线程/场景线程语义。
对音频类组件来说,虽然会与 `AudioSystem` 交互,但这不代表 `Component` 基类本身具备线程同步能力。
## 当前实现限制
- `transform()` 对未附着组件是未定义用法,因为实现里没有 null check。
- 基类不区分“已构造”“已挂接”“已进入场景”“已启动”等更细粒度状态。
- 没有统一的反射、属性枚举或编辑器元数据系统;文档页只能按实际 public API 解释。
## 相关方法
- [Awake](Awake.md)
- [Start](Start.md)
- [Update](Update.md)
- [FixedUpdate](FixedUpdate.md)
- [LateUpdate](LateUpdate.md)
- [OnEnable](OnEnable.md)
- [OnDisable](OnDisable.md)
- [OnDestroy](OnDestroy.md)
- [GetGameObject](GetGameObject.md)
- [transform](transform.md)
- [GetScene](GetScene.md)
- [IsEnabled](IsEnabled.md)
- [SetEnabled](SetEnabled.md)
- [Serialize](Serialize.md)
- [Deserialize](Deserialize.md)
## 相关指南
- [GameObject-Component Lifecycle And Serialization](../../../_guides/Components/GameObject-Component-Lifecycle-And-Serialization.md)
## 相关文档
- [当前模块](../Components.md)
- [GameObject](../GameObject/GameObject.md)
- [TransformComponent](../TransformComponent/TransformComponent.md)
- [API 总索引](../../../main.md)