2026-03-26 16:45:24 +08:00
|
|
|
|
# LayerStack
|
|
|
|
|
|
|
|
|
|
|
|
**命名空间**: `XCEngine::Core`
|
|
|
|
|
|
|
|
|
|
|
|
**类型**: `class`
|
|
|
|
|
|
|
|
|
|
|
|
**头文件**: `XCEngine/Core/LayerStack.h`
|
|
|
|
|
|
|
2026-03-27 19:18:53 +08:00
|
|
|
|
**描述**: 一个按“普通层 + overlay”分段组织的 `Layer` 容器,负责遍历和基础生命周期分发。
|
|
|
|
|
|
|
|
|
|
|
|
## 角色概述
|
|
|
|
|
|
|
|
|
|
|
|
`LayerStack` 负责管理多个 [Layer](../Layer/Layer.md) 实例的顺序关系。它把容器分成两段:
|
|
|
|
|
|
|
|
|
|
|
|
- 普通 layers
|
|
|
|
|
|
- overlays
|
|
|
|
|
|
|
|
|
|
|
|
这是一种常见的应用壳层设计,适合把“主功能层”和“悬浮 UI / 调试覆盖层”分开组织。
|
|
|
|
|
|
|
|
|
|
|
|
## 当前实现行为
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 所有权由 `std::unique_ptr<Layer>` 表达
|
|
|
|
|
|
|
|
|
|
|
|
`LayerStack` 内部直接持有:
|
|
|
|
|
|
|
|
|
|
|
|
`std::vector<std::unique_ptr<Layer>> m_layers`
|
|
|
|
|
|
|
|
|
|
|
|
因此:
|
|
|
|
|
|
|
|
|
|
|
|
- stack 拥有 layer 生命周期
|
|
|
|
|
|
- `pushLayer()` / `pushOverlay()` 都会转移 unique ownership
|
|
|
|
|
|
- `popLayer()` / `popOverlay()` 删除元素时会触发对象析构
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 普通层和 overlay 的分界靠 `m_layerInsertIndex`
|
|
|
|
|
|
|
|
|
|
|
|
`pushLayer()` 会把新层插入 `m_layers.begin() + m_layerInsertIndex`,然后递增索引;`pushOverlay()` 则直接追加到尾部。
|
|
|
|
|
|
|
|
|
|
|
|
这意味着当前排序规则是:
|
|
|
|
|
|
|
|
|
|
|
|
- 普通层保持在前半段
|
|
|
|
|
|
- overlay 永远位于后半段
|
|
|
|
|
|
|
|
|
|
|
|
### 3. `push*` 不会自动调用 `onAttach()`
|
|
|
|
|
|
|
|
|
|
|
|
这是一个非常重要的当前行为。很多引擎框架会在 push 时立刻 attach,但当前实现不会:
|
|
|
|
|
|
|
|
|
|
|
|
- `pushLayer()` 只做插入
|
|
|
|
|
|
- `pushOverlay()` 只做插入
|
|
|
|
|
|
|
|
|
|
|
|
真正的 attach 分发只发生在显式调用 [onAttach](onAttach.md) 时。
|
|
|
|
|
|
|
|
|
|
|
|
### 4. `pop*` 会调用 `onDetach()`
|
|
|
|
|
|
|
|
|
|
|
|
相对地,`popLayer()` 和 `popOverlay()` 在删除元素前都会先调用对应 layer 的 `onDetach()`。
|
|
|
|
|
|
|
|
|
|
|
|
### 5. 遍历顺序是正向遍历
|
|
|
|
|
|
|
|
|
|
|
|
以下分发方法当前都按 `m_layers` 的正向顺序调用:
|
|
|
|
|
|
|
|
|
|
|
|
- `onUpdate()`
|
|
|
|
|
|
- `onEvent()`
|
|
|
|
|
|
- `onImGuiRender()`
|
|
|
|
|
|
- `onAttach()`
|
|
|
|
|
|
- `onDetach()`
|
|
|
|
|
|
|
|
|
|
|
|
这尤其意味着 `onEvent()` 不是“从 top-most overlay 逆向往下传”的模式,而是从前到后正向调用。对有事件吞噬需求的系统来说,这一点必须明确。
|
|
|
|
|
|
|
|
|
|
|
|
## 迭代器暴露
|
|
|
|
|
|
|
|
|
|
|
|
`LayerStack` 同时暴露了:
|
|
|
|
|
|
|
|
|
|
|
|
- `begin()` / `end()`
|
|
|
|
|
|
- `rbegin()` / `rend()`
|
|
|
|
|
|
- `cbegin()` / `cend()`
|
|
|
|
|
|
- `crbegin()` / `crend()`
|
|
|
|
|
|
|
|
|
|
|
|
这让外部可以按需要自定义遍历顺序,但也说明它没有封装成强约束的调度器。
|
|
|
|
|
|
|
|
|
|
|
|
## 当前代码库中的使用情况
|
|
|
|
|
|
|
|
|
|
|
|
在当前取证范围内,没有看到它在 `engine/src` 里形成广泛调用链。因此这更像基础应用框架能力,而不是当前引擎主运行时的核心主线。
|
|
|
|
|
|
|
|
|
|
|
|
## 线程语义
|
|
|
|
|
|
|
|
|
|
|
|
- 当前实现没有加锁。
|
|
|
|
|
|
- 所有修改和遍历都应按单线程外部驱动理解。
|
|
|
|
|
|
|
|
|
|
|
|
## 当前实现限制
|
|
|
|
|
|
|
|
|
|
|
|
- `pushLayer()` / `pushOverlay()` 不会自动 `onAttach()`。
|
|
|
|
|
|
- `onDetach()` 在 `pop*` 时会调用,但析构函数本身是默认实现,不会自动遍历 detach 剩余层。
|
|
|
|
|
|
- `onEvent()` 采用正向遍历,不是常见的逆向 overlay 优先分发。
|
|
|
|
|
|
- 没有看到直接测试覆盖。
|
|
|
|
|
|
|
|
|
|
|
|
## 相关方法
|
|
|
|
|
|
|
|
|
|
|
|
- [Constructor](Constructor.md)
|
|
|
|
|
|
- [Destructor](Destructor.md)
|
|
|
|
|
|
- [pushLayer](pushLayer.md)
|
|
|
|
|
|
- [pushOverlay](pushOverlay.md)
|
|
|
|
|
|
- [popLayer](popLayer.md)
|
|
|
|
|
|
- [popOverlay](popOverlay.md)
|
|
|
|
|
|
- [onUpdate](onUpdate.md)
|
|
|
|
|
|
- [onEvent](onEvent.md)
|
|
|
|
|
|
- [onImGuiRender](onImGuiRender.md)
|
|
|
|
|
|
- [onAttach](onAttach.md)
|
|
|
|
|
|
- [onDetach](onDetach.md)
|
|
|
|
|
|
- [begin](begin.md)
|
|
|
|
|
|
- [end](end.md)
|
|
|
|
|
|
- [rbegin](rbegin.md)
|
|
|
|
|
|
- [rend](rend.md)
|
|
|
|
|
|
- [cbegin](cbegin.md)
|
|
|
|
|
|
- [cend](cend.md)
|
|
|
|
|
|
- [crbegin](crbegin.md)
|
|
|
|
|
|
- [crend](crend.md)
|
|
|
|
|
|
|
|
|
|
|
|
## 相关指南
|
|
|
|
|
|
|
|
|
|
|
|
- [Core Foundations: Ownership, Events, And Layers](../../../_guides/Core/Core-Foundations-Ownership-Events-And-Layers.md)
|
2026-03-26 16:45:24 +08:00
|
|
|
|
|
|
|
|
|
|
## 相关文档
|
|
|
|
|
|
|
2026-03-27 19:18:53 +08:00
|
|
|
|
- [当前模块](../Core.md)
|
|
|
|
|
|
- [Layer](../Layer/Layer.md)
|
|
|
|
|
|
- [API 总索引](../../../main.md)
|