273 lines
6.7 KiB
TypeScript
273 lines
6.7 KiB
TypeScript
/**
|
||
* Preview Scene Service
|
||
* 预览场景服务
|
||
*
|
||
* Manages isolated preview scenes for editor tools (tilemap editor, material preview, etc.)
|
||
* 管理编辑器工具的隔离预览场景(瓦片地图编辑器、材质预览等)
|
||
*/
|
||
|
||
import { Scene, EntitySystem, Entity } from '@esengine/ecs-framework';
|
||
|
||
/**
|
||
* Configuration for creating a preview scene
|
||
* 创建预览场景的配置
|
||
*/
|
||
export interface PreviewSceneConfig {
|
||
/** Unique identifier for the preview scene | 预览场景的唯一标识符 */
|
||
id: string;
|
||
/** Scene name | 场景名称 */
|
||
name?: string;
|
||
/** Systems to add to the scene | 要添加到场景的系统 */
|
||
systems?: EntitySystem[];
|
||
/** Initial clear color | 初始清除颜色 */
|
||
clearColor?: { r: number; g: number; b: number; a: number };
|
||
}
|
||
|
||
/**
|
||
* Represents an isolated preview scene for editor tools
|
||
* 表示编辑器工具的隔离预览场景
|
||
*/
|
||
export interface IPreviewScene {
|
||
/** Scene instance | 场景实例 */
|
||
readonly scene: Scene;
|
||
/** Unique identifier | 唯一标识符 */
|
||
readonly id: string;
|
||
/** Scene name | 场景名称 */
|
||
readonly name: string;
|
||
/** Clear color | 清除颜色 */
|
||
clearColor: { r: number; g: number; b: number; a: number };
|
||
|
||
/**
|
||
* Create a temporary entity (auto-cleaned on dispose)
|
||
* 创建临时实体(dispose 时自动清理)
|
||
*/
|
||
createEntity(name: string): Entity;
|
||
|
||
/**
|
||
* Remove a temporary entity
|
||
* 移除临时实体
|
||
*/
|
||
removeEntity(entity: Entity): void;
|
||
|
||
/**
|
||
* Get all entities in the scene
|
||
* 获取场景中的所有实体
|
||
*/
|
||
getEntities(): readonly Entity[];
|
||
|
||
/**
|
||
* Clear all temporary entities
|
||
* 清除所有临时实体
|
||
*/
|
||
clearEntities(): void;
|
||
|
||
/**
|
||
* Add a system to the scene
|
||
* 向场景添加系统
|
||
*/
|
||
addSystem(system: EntitySystem): void;
|
||
|
||
/**
|
||
* Remove a system from the scene
|
||
* 从场景移除系统
|
||
*/
|
||
removeSystem(system: EntitySystem): void;
|
||
|
||
/**
|
||
* Update the scene (process systems)
|
||
* 更新场景(处理系统)
|
||
*/
|
||
update(deltaTime: number): void;
|
||
|
||
/**
|
||
* Dispose the preview scene
|
||
* 释放预览场景
|
||
*/
|
||
dispose(): void;
|
||
}
|
||
|
||
/**
|
||
* Preview scene implementation
|
||
* 预览场景实现
|
||
*/
|
||
class PreviewScene implements IPreviewScene {
|
||
readonly scene: Scene;
|
||
readonly id: string;
|
||
readonly name: string;
|
||
clearColor: { r: number; g: number; b: number; a: number };
|
||
|
||
private _entities: Set<Entity> = new Set();
|
||
private _disposed = false;
|
||
|
||
constructor(config: PreviewSceneConfig) {
|
||
this.id = config.id;
|
||
this.name = config.name ?? `PreviewScene_${config.id}`;
|
||
this.clearColor = config.clearColor ?? { r: 0.1, g: 0.1, b: 0.12, a: 1.0 };
|
||
|
||
// Create isolated scene
|
||
this.scene = new Scene({ name: this.name });
|
||
|
||
// Add configured systems
|
||
if (config.systems) {
|
||
for (const system of config.systems) {
|
||
this.scene.addSystem(system);
|
||
}
|
||
}
|
||
}
|
||
|
||
createEntity(name: string): Entity {
|
||
if (this._disposed) {
|
||
throw new Error(`PreviewScene ${this.id} is disposed`);
|
||
}
|
||
|
||
const entity = this.scene.createEntity(name);
|
||
this._entities.add(entity);
|
||
return entity;
|
||
}
|
||
|
||
removeEntity(entity: Entity): void {
|
||
if (this._disposed) return;
|
||
|
||
if (this._entities.has(entity)) {
|
||
this._entities.delete(entity);
|
||
this.scene.destroyEntities([entity]);
|
||
}
|
||
}
|
||
|
||
getEntities(): readonly Entity[] {
|
||
return Array.from(this._entities);
|
||
}
|
||
|
||
clearEntities(): void {
|
||
if (this._disposed) return;
|
||
|
||
const entities = Array.from(this._entities);
|
||
if (entities.length > 0) {
|
||
this.scene.destroyEntities(entities);
|
||
}
|
||
this._entities.clear();
|
||
}
|
||
|
||
addSystem(system: EntitySystem): void {
|
||
if (this._disposed) return;
|
||
this.scene.addSystem(system);
|
||
}
|
||
|
||
removeSystem(system: EntitySystem): void {
|
||
if (this._disposed) return;
|
||
this.scene.removeSystem(system);
|
||
}
|
||
|
||
update(_deltaTime: number): void {
|
||
if (this._disposed) return;
|
||
this.scene.update();
|
||
}
|
||
|
||
dispose(): void {
|
||
if (this._disposed) return;
|
||
this._disposed = true;
|
||
|
||
// Clear all entities
|
||
this.clearEntities();
|
||
|
||
// Scene cleanup is handled by GC
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Preview Scene Service - manages all preview scenes
|
||
* 预览场景服务 - 管理所有预览场景
|
||
*/
|
||
export class PreviewSceneService {
|
||
private static _instance: PreviewSceneService | null = null;
|
||
private _scenes: Map<string, PreviewScene> = new Map();
|
||
|
||
private constructor() {}
|
||
|
||
/**
|
||
* Get singleton instance
|
||
* 获取单例实例
|
||
*/
|
||
static getInstance(): PreviewSceneService {
|
||
if (!PreviewSceneService._instance) {
|
||
PreviewSceneService._instance = new PreviewSceneService();
|
||
}
|
||
return PreviewSceneService._instance;
|
||
}
|
||
|
||
/**
|
||
* Create a new preview scene
|
||
* 创建新的预览场景
|
||
*/
|
||
createScene(config: PreviewSceneConfig): IPreviewScene {
|
||
if (this._scenes.has(config.id)) {
|
||
throw new Error(`Preview scene with id "${config.id}" already exists`);
|
||
}
|
||
|
||
const scene = new PreviewScene(config);
|
||
this._scenes.set(config.id, scene);
|
||
return scene;
|
||
}
|
||
|
||
/**
|
||
* Get a preview scene by ID
|
||
* 通过 ID 获取预览场景
|
||
*/
|
||
getScene(id: string): IPreviewScene | null {
|
||
return this._scenes.get(id) ?? null;
|
||
}
|
||
|
||
/**
|
||
* Check if a preview scene exists
|
||
* 检查预览场景是否存在
|
||
*/
|
||
hasScene(id: string): boolean {
|
||
return this._scenes.has(id);
|
||
}
|
||
|
||
/**
|
||
* Dispose a preview scene
|
||
* 释放预览场景
|
||
*/
|
||
disposeScene(id: string): void {
|
||
const scene = this._scenes.get(id);
|
||
if (scene) {
|
||
scene.dispose();
|
||
this._scenes.delete(id);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get all preview scene IDs
|
||
* 获取所有预览场景 ID
|
||
*/
|
||
getSceneIds(): string[] {
|
||
return Array.from(this._scenes.keys());
|
||
}
|
||
|
||
/**
|
||
* Dispose all preview scenes
|
||
* 释放所有预览场景
|
||
*/
|
||
disposeAll(): void {
|
||
for (const scene of this._scenes.values()) {
|
||
scene.dispose();
|
||
}
|
||
this._scenes.clear();
|
||
}
|
||
|
||
/**
|
||
* Dispose the service
|
||
* 释放服务
|
||
*/
|
||
dispose(): void {
|
||
this.disposeAll();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Service identifier for dependency injection
|
||
* 依赖注入的服务标识符
|
||
*/
|
||
export const IPreviewSceneService = Symbol.for('IPreviewSceneService');
|