2025-06-09 14:51:26 +08:00
|
|
|
|
import { Entity } from '../Entity';
|
|
|
|
|
|
import { Core } from '../../Core';
|
|
|
|
|
|
import { Matcher } from '../Utils/Matcher';
|
|
|
|
|
|
import { PerformanceMonitor } from '../../Utils/PerformanceMonitor';
|
|
|
|
|
|
import type { Scene } from '../Scene';
|
2025-06-30 20:43:11 +08:00
|
|
|
|
import type { ISystemBase } from '../../Types';
|
2025-06-09 14:51:26 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 实体系统的基类
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用于处理一组符合特定条件的实体。系统是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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 系统初始化
|
|
|
|
|
|
*
|
2025-06-19 15:00:14 +08:00
|
|
|
|
* 在系统创建时调用,自动检查场景中已存在的实体是否匹配此系统。
|
|
|
|
|
|
* 子类可以重写此方法进行额外的初始化操作。
|
2025-06-09 14:51:26 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public initialize(): void {
|
2025-06-19 15:00:14 +08:00
|
|
|
|
if (this.scene?.entities?.buffer) {
|
|
|
|
|
|
for (const entity of this.scene.entities.buffer) {
|
|
|
|
|
|
this.onChanged(entity);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 子类可以重写此方法进行额外初始化
|
2025-06-09 14:51:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 当实体的组件发生变化时调用
|
|
|
|
|
|
*
|
|
|
|
|
|
* 检查实体是否仍然符合系统的匹配条件,并相应地添加或移除实体。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @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}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|