120 lines
3.5 KiB
Markdown
120 lines
3.5 KiB
Markdown
# Script 组件分析
|
||
|
||
## 组件职责
|
||
|
||
`Script.*` 负责:
|
||
|
||
- 脚本类型注册与脚本实例创建;
|
||
- `script_id` 生命周期管理;
|
||
- 脚本逐帧更新;
|
||
- 脚本对 Transform 的延迟写回。
|
||
|
||
## 核心存储
|
||
|
||
`Script.cpp` 的关键结构:
|
||
|
||
- `entity_scripts`:活跃脚本实例池
|
||
- `id_mapping`:`script_id` 索引到实例池下标
|
||
- `generations + free_ids`:脚本 ID 代数与复用队列
|
||
- `transform_cache`:脚本写变换的缓存数组
|
||
- `cache_map`:Transform ID 到缓存下标映射
|
||
|
||
## 注册机制
|
||
|
||
脚本工厂注册表:
|
||
|
||
- 类型:`unordered_map<size_t, script_creator>`
|
||
- `register_script(tag, func)` 注册工厂
|
||
- `get_script_creator(tag)` 查询工厂
|
||
|
||
通常由 `REGISTER_SCRIPT` 宏在静态初始化阶段完成注册。
|
||
|
||
## 创建流程
|
||
|
||
`script::create(init_info, entity)`:
|
||
|
||
1. 校验实体有效与工厂函数有效;
|
||
2. 分配 `script_id`(复用或新建);
|
||
3. 调用工厂创建脚本实例并压入 `entity_scripts`;
|
||
4. 写入 `id_mapping`;
|
||
5. 返回 `script::component` 句柄。
|
||
|
||
## 删除流程
|
||
|
||
`script::remove(component c)`:
|
||
|
||
- 校验组件存在;
|
||
- 用无序删除移除脚本实例;
|
||
- 修正被交换元素的 `id_mapping`;
|
||
- 将被删 id 的映射标记为无效。
|
||
|
||
## 更新与缓存提交流程
|
||
|
||
`script::update(dt)` 包含两段:
|
||
|
||
1. 遍历 `entity_scripts` 执行每个脚本的 `update(dt)`;
|
||
2. 若 `transform_cache` 非空,统一调用 `transform::update(...)` 提交后清空。
|
||
|
||
这使脚本阶段不直接写 Transform 主数组,减少帧内重复写。
|
||
|
||
## 脚本写 Transform 的方式
|
||
|
||
`entity_script::set_rotation/position/...` 的行为是:
|
||
|
||
- 先通过 `get_cache_ptr(entity)` 找到该实体缓存槽;
|
||
- 设置对应 `flags`;
|
||
- 写入新值到 cache;
|
||
- 等待帧末统一提交。
|
||
|
||
## 设计特点
|
||
|
||
- 句柄安全:`script_id` 采用 generation 机制;
|
||
- 批处理友好:Transform 写入集中提交;
|
||
- 解耦:脚本逻辑与 Transform 存储细节隔离。
|
||
|
||
## 三条主线时序图(注册、生命周期、缓存提交)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
autonumber
|
||
participant Macro as REGISTER_SCRIPT
|
||
participant Detail as script::detail
|
||
participant Registry as script_registry
|
||
participant Entity as game_entity::entity
|
||
participant ScriptSys as script::system
|
||
participant Obj as entity_script
|
||
participant Cache as transform_cache
|
||
participant Trans as transform::system
|
||
|
||
rect rgb(236, 248, 255)
|
||
Note over Macro,Registry: 主线一:脚本类型注册
|
||
Macro->>Detail: register_script(tag, creator)
|
||
Detail->>Registry: insert(tag, creator)
|
||
Registry-->>Detail: creator 已登记
|
||
end
|
||
|
||
rect rgb(239, 252, 240)
|
||
Note over Entity,ScriptSys: 主线二:脚本实例生命周期
|
||
Entity->>ScriptSys: create(init_info, entity)
|
||
ScriptSys->>ScriptSys: 分配或复用 script_id
|
||
ScriptSys->>Registry: get_script_creator(tag)
|
||
Registry-->>ScriptSys: 返回 creator
|
||
ScriptSys->>Obj: creator(entity)
|
||
Obj-->>ScriptSys: 生成脚本实例
|
||
ScriptSys->>ScriptSys: 写入 entity_scripts 与 id_mapping
|
||
ScriptSys-->>Entity: 返回 script::component
|
||
Entity->>ScriptSys: remove(component)
|
||
ScriptSys->>ScriptSys: erase_unordered + 修正 id_mapping
|
||
end
|
||
|
||
rect rgb(255, 246, 236)
|
||
Note over Obj,Trans: 主线三:脚本写变换缓存并帧末提交
|
||
ScriptSys->>Obj: update(dt)
|
||
Obj->>Cache: set_position/rotation/scale...
|
||
Cache-->>Obj: flags + value 已缓存
|
||
ScriptSys->>Trans: transform::update(cache, count)
|
||
Trans-->>ScriptSys: 写入完成
|
||
ScriptSys->>Cache: clear()
|
||
end
|
||
```
|