feat(core): 添加持久化实体支持跨场景迁移

实现实体生命周期策略,允许标记实体为持久化,在场景切换时自动迁移到新场景。

主要变更:
- 新增 EEntityLifecyclePolicy 枚举(SceneLocal/Persistent)
- Entity 添加 setPersistent()、setSceneLocal()、isPersistent API
- Scene 添加 findPersistentEntities()、extractPersistentEntities()、receiveMigratedEntities()
- SceneManager.setScene() 自动处理持久化实体迁移
- 添加完整的中英文文档和 21 个测试用例
This commit is contained in:
yhh
2025-12-05 22:46:53 +08:00
parent 3d5fcc1a55
commit 8f9a7d8581
15 changed files with 2158 additions and 5 deletions

View File

@@ -0,0 +1,26 @@
/**
* 实体生命周期策略
*
* 定义实体在场景切换时的行为。
*
* Entity lifecycle policy.
* Defines entity behavior during scene transitions.
*/
export const enum EEntityLifecyclePolicy {
/**
* 默认策略 - 随场景销毁
*
* Default policy - destroyed with scene.
*/
SceneLocal = 0,
/**
* 持久化策略 - 跨场景保留
*
* 实体在场景切换时自动迁移到新场景。
*
* Persistent policy - survives scene transitions.
* Entity is automatically migrated to the new scene.
*/
Persistent = 1
}

View File

@@ -1,5 +1,6 @@
import { Component } from './Component';
import { ComponentRegistry, ComponentType } from './Core/ComponentStorage';
import { EEntityLifecyclePolicy } from './Core/EntityLifecyclePolicy';
import { BitMask64Utils, BitMask64Data } from './Utils/BigIntCompatibility';
import { createLogger } from '../Utils/Logger';
import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators';
@@ -118,6 +119,13 @@ export class Entity {
*/
private _componentCache: Component[] | null = null;
/**
* 生命周期策略
*
* Lifecycle policy for scene transitions.
*/
private _lifecyclePolicy: EEntityLifecyclePolicy = EEntityLifecyclePolicy.SceneLocal;
/**
* 构造函数
*
@@ -129,6 +137,61 @@ export class Entity {
this.id = id;
}
/**
* 获取生命周期策略
*
* Get lifecycle policy.
*/
public get lifecyclePolicy(): EEntityLifecyclePolicy {
return this._lifecyclePolicy;
}
/**
* 检查实体是否为持久化实体
*
* Check if entity is persistent (survives scene transitions).
*/
public get isPersistent(): boolean {
return this._lifecyclePolicy === EEntityLifecyclePolicy.Persistent;
}
/**
* 设置实体为持久化(跨场景保留)
*
* 标记后的实体在场景切换时不会被销毁,会自动迁移到新场景。
*
* Mark entity as persistent (survives scene transitions).
* Persistent entities are automatically migrated to the new scene.
*
* @returns this支持链式调用 | Returns this for chaining
*
* @example
* ```typescript
* const player = scene.createEntity('Player')
* .setPersistent()
* .addComponent(new PlayerComponent());
* ```
*/
public setPersistent(): this {
this._lifecyclePolicy = EEntityLifecyclePolicy.Persistent;
return this;
}
/**
* 设置实体为场景本地(随场景销毁)
*
* 将实体恢复为默认行为。
*
* Mark entity as scene-local (destroyed with scene).
* Restores default behavior.
*
* @returns this支持链式调用 | Returns this for chaining
*/
public setSceneLocal(): this {
this._lifecyclePolicy = EEntityLifecyclePolicy.SceneLocal;
return this;
}
/**
* 获取销毁状态
* @returns 如果实体已被销毁则返回true

View File

@@ -819,6 +819,81 @@ export class Scene implements IScene {
return result;
}
/**
* 查找所有持久化实体
*
* Find all persistent entities in this scene.
*
* @returns 持久化实体数组 | Array of persistent entities
*/
public findPersistentEntities(): Entity[] {
return this.entities.buffer.filter(entity => entity.isPersistent);
}
/**
* 提取持久化实体(从场景中分离但不销毁)
*
* 用于场景切换时收集需要迁移的实体。
*
* Extract persistent entities (detach from scene without destroying).
* Used during scene transitions to collect entities for migration.
*
* @returns 被提取的持久化实体数组 | Array of extracted persistent entities
*
* @internal
*/
public extractPersistentEntities(): Entity[] {
const persistentEntities = this.findPersistentEntities();
for (const entity of persistentEntities) {
// 从实体列表移除
this.entities.remove(entity);
// 从查询系统移除
this.querySystem.removeEntity(entity);
// 清除场景引用(但保留组件数据)
entity.scene = null;
}
return persistentEntities;
}
/**
* 接收迁移的实体
*
* 将从其他场景迁移来的实体添加到当前场景。
*
* Receive migrated entities from another scene.
*
* @param entities 要接收的实体数组 | Entities to receive
*
* @internal
*/
public receiveMigratedEntities(entities: Entity[]): void {
for (const entity of entities) {
// 设置新场景引用
entity.scene = this;
// 添加到实体列表
this.entities.add(entity);
// 添加到查询系统
this.querySystem.addEntity(entity);
// 重新注册组件到新场景的存储
for (const component of entity.components) {
this.componentStorageManager.addComponent(entity.id, component);
this.referenceTracker?.registerEntityScene(entity.id, this);
}
}
// 清除系统缓存
if (entities.length > 0) {
this.clearSystemEntityCaches();
}
}
/**
* 根据名称查找实体(别名方法)
*

View File

@@ -1,4 +1,6 @@
import { IScene } from './IScene';
import { Scene } from './Scene';
import { Entity } from './Entity';
import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI';
import { Time } from '../Utils/Time';
import { createLogger } from '../Utils/Logger';
@@ -79,6 +81,13 @@ export class SceneManager implements IService {
*/
private _performanceMonitor: PerformanceMonitor | null = null;
/**
* 待迁移的持久化实体
*
* Pending persistent entities for migration.
*/
private _pendingPersistentEntities: Entity[] = [];
/**
* 默认场景ID
*/
@@ -104,17 +113,33 @@ export class SceneManager implements IService {
* 设置当前场景(立即切换)
*
* 会自动处理旧场景的结束和新场景的初始化。
* 持久化实体会自动迁移到新场景。
*
* @param scene - 要设置的场景实例
* @returns 返回设置的场景实例,便于链式调用
* Set current scene (immediate transition).
* Automatically handles old scene cleanup and new scene initialization.
* Persistent entities are automatically migrated to the new scene.
*
* @param scene - 要设置的场景实例 | Scene instance to set
* @returns 返回设置的场景实例,便于链式调用 | Returns the scene for chaining
*
* @example
* ```typescript
* const gameScene = sceneManager.setScene(new GameScene());
* console.log(gameScene.name); // 可以立即使用返回的场景
* console.log(gameScene.name);
* ```
*/
public setScene<T extends IScene>(scene: T): T {
// 从当前场景提取持久化实体
const currentScene = this.currentScene;
if (currentScene && currentScene instanceof Scene) {
this._pendingPersistentEntities = currentScene.extractPersistentEntities();
if (this._pendingPersistentEntities.length > 0) {
this._logger.debug(
`Extracted ${this._pendingPersistentEntities.length} persistent entities for migration`
);
}
}
// 移除旧场景
this._defaultWorld.removeAllScenes();
@@ -127,6 +152,15 @@ export class SceneManager implements IService {
this._defaultWorld.createScene(SceneManager.DEFAULT_SCENE_ID, scene);
this._defaultWorld.setSceneActive(SceneManager.DEFAULT_SCENE_ID, true);
// 迁移持久化实体到新场景
if (this._pendingPersistentEntities.length > 0 && scene instanceof Scene) {
scene.receiveMigratedEntities(this._pendingPersistentEntities);
this._logger.debug(
`Migrated ${this._pendingPersistentEntities.length} persistent entities to new scene`
);
this._pendingPersistentEntities = [];
}
// 重建ECS API
if (scene.querySystem && scene.eventSystem) {
this._ecsAPI = createECSAPI(scene, scene.querySystem, scene.eventSystem);

View File

@@ -1,5 +1,6 @@
export { Entity } from './Entity';
export { Component } from './Component';
export { EEntityLifecyclePolicy } from './Core/EntityLifecyclePolicy';
export { ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator } from './CoreEvents';
export * from './Systems';
export * from './Utils';