Files
esengine/src/ECS/Systems/EntitySystem.ts
2025-06-30 20:43:11 +08:00

326 lines
8.2 KiB
TypeScript
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.
import { Entity } from '../Entity';
import { Core } from '../../Core';
import { Matcher } from '../Utils/Matcher';
import { PerformanceMonitor } from '../../Utils/PerformanceMonitor';
import type { Scene } from '../Scene';
import type { ISystemBase } from '../../Types';
/**
* 实体系统的基类
*
* 用于处理一组符合特定条件的实体。系统是ECS架构中的逻辑处理单元
* 负责对拥有特定组件组合的实体执行业务逻辑。
*
* @example
* ```typescript
* class MovementSystem extends EntitySystem {
* constructor() {
* super(Matcher.empty().all(Transform, Velocity));
* }
*
* protected process(entities: Entity[]): void {
* for (const entity of entities) {
* const transform = entity.getComponent(Transform);
* const velocity = entity.getComponent(Velocity);
* transform.position.add(velocity.value);
* }
* }
* }
* ```
*/
export abstract class EntitySystem implements ISystemBase {
private _entities: Entity[] = [];
private _updateOrder: number = 0;
private _enabled: boolean = true;
private _performanceMonitor = PerformanceMonitor.instance;
private _systemName: string;
/**
* 获取系统处理的实体列表
*/
public get entities(): readonly Entity[] {
return this._entities;
}
/**
* 获取系统的更新时序
*/
public get updateOrder(): number {
return this._updateOrder;
}
public set updateOrder(value: number) {
this.setUpdateOrder(value);
}
/**
* 获取系统的启用状态
*/
public get enabled(): boolean {
return this._enabled;
}
/**
* 设置系统的启用状态
*/
public set enabled(value: boolean) {
this._enabled = value;
}
/**
* 获取系统名称
*/
public get systemName(): string {
return this._systemName;
}
constructor(matcher?: Matcher) {
this._matcher = matcher ? matcher : Matcher.empty();
this._systemName = this.constructor.name;
}
private _scene!: Scene;
/**
* 这个系统所属的场景
*/
public get scene(): Scene {
return this._scene;
}
public set scene(value: Scene) {
this._scene = value;
this._entities = [];
}
private _matcher: Matcher;
/**
* 获取实体匹配器
*/
public get matcher(): Matcher {
return this._matcher;
}
/**
* 设置更新时序
* @param order 更新时序
*/
public setUpdateOrder(order: number): void {
this._updateOrder = order;
this.scene.entityProcessors.setDirty();
}
/**
* 系统初始化
*
* 在系统创建时调用,自动检查场景中已存在的实体是否匹配此系统。
* 子类可以重写此方法进行额外的初始化操作。
*/
public initialize(): void {
if (this.scene?.entities?.buffer) {
for (const entity of this.scene.entities.buffer) {
this.onChanged(entity);
}
}
// 子类可以重写此方法进行额外初始化
}
/**
* 当实体的组件发生变化时调用
*
* 检查实体是否仍然符合系统的匹配条件,并相应地添加或移除实体。
*
* @param entity 发生变化的实体
*/
public onChanged(entity: Entity): void {
const contains = this._entities.includes(entity);
const interest = this._matcher.isInterestedEntity(entity);
if (interest && !contains) {
this.add(entity);
} else if (!interest && contains) {
this.remove(entity);
}
}
/**
* 添加实体到系统
*
* @param entity 要添加的实体
*/
public add(entity: Entity): void {
if (!this._entities.includes(entity)) {
this._entities.push(entity);
this.onAdded(entity);
}
}
/**
* 当实体被添加到系统时调用
*
* 子类可以重写此方法来处理实体添加事件。
*
* @param entity 被添加的实体
*/
protected onAdded(entity: Entity): void {
// 子类可以重写此方法
}
/**
* 从系统中移除实体
*
* @param entity 要移除的实体
*/
public remove(entity: Entity): void {
const index = this._entities.indexOf(entity);
if (index !== -1) {
this._entities.splice(index, 1);
this.onRemoved(entity);
}
}
/**
* 当实体从系统中移除时调用
*
* 子类可以重写此方法来处理实体移除事件。
*
* @param entity 被移除的实体
*/
protected onRemoved(entity: Entity): void {
// 子类可以重写此方法
}
/**
* 更新系统
*
* 在每帧调用,处理系统的主要逻辑。
*/
public update(): void {
if (!this._enabled || !this.checkProcessing()) {
return;
}
const startTime = this._performanceMonitor.startMonitoring(this._systemName);
try {
this.begin();
this.process(this._entities);
} finally {
this._performanceMonitor.endMonitoring(this._systemName, startTime, this._entities.length);
}
}
/**
* 后期更新系统
*
* 在所有系统的update方法执行完毕后调用。
*/
public lateUpdate(): void {
if (!this._enabled || !this.checkProcessing()) {
return;
}
const startTime = this._performanceMonitor.startMonitoring(`${this._systemName}_Late`);
try {
this.lateProcess(this._entities);
this.end();
} finally {
this._performanceMonitor.endMonitoring(`${this._systemName}_Late`, startTime, this._entities.length);
}
}
/**
* 在系统处理开始前调用
*
* 子类可以重写此方法进行预处理操作。
*/
protected begin(): void {
// 子类可以重写此方法
}
/**
* 处理实体列表
*
* 系统的核心逻辑,子类必须实现此方法来定义具体的处理逻辑。
*
* @param entities 要处理的实体列表
*/
protected process(entities: Entity[]): void {
// 子类必须实现此方法
}
/**
* 后期处理实体列表
*
* 在主要处理逻辑之后执行,子类可以重写此方法。
*
* @param entities 要处理的实体列表
*/
protected lateProcess(entities: Entity[]): void {
// 子类可以重写此方法
}
/**
* 系统处理完毕后调用
*
* 子类可以重写此方法进行后处理操作。
*/
protected end(): void {
// 子类可以重写此方法
}
/**
* 检查系统是否需要处理
*
* 在启用系统时有用,但仅偶尔需要处理。
* 这只影响处理,不影响事件或订阅列表。
*
* @returns 如果系统应该处理则为true如果不处理则为false
*/
protected checkProcessing(): boolean {
return true;
}
/**
* 获取系统的性能数据
*
* @returns 性能数据或undefined
*/
public getPerformanceData() {
return this._performanceMonitor.getSystemData(this._systemName);
}
/**
* 获取系统的性能统计
*
* @returns 性能统计或undefined
*/
public getPerformanceStats() {
return this._performanceMonitor.getSystemStats(this._systemName);
}
/**
* 重置系统的性能数据
*/
public resetPerformanceData(): void {
this._performanceMonitor.resetSystem(this._systemName);
}
/**
* 获取系统信息的字符串表示
*
* @returns 系统信息字符串
*/
public toString(): string {
const entityCount = this._entities.length;
const perfData = this.getPerformanceData();
const perfInfo = perfData ? ` (${perfData.executionTime.toFixed(2)}ms)` : '';
return `${this._systemName}[${entityCount} entities]${perfInfo}`;
}
}