Files
esengine/packages/core/src/ECS/Systems/EntitySystem.ts
YHH cd6ef222d1 feat(ecs): 核心系统改进 - 句柄、调度、变更检测与查询编译 (#304)
新增功能:
- EntityHandle: 轻量级实体句柄 (28位索引 + 20位代数)
- SystemScheduler: 声明式系统调度,支持 @Stage/@Before/@After/@InSet 装饰器
- EpochManager: 帧级变更检测
- CompiledQuery: 预编译类型安全查询

API 改进:
- EntitySystem 添加 getBefore()/getAfter()/getSets() getter 方法
- Entity 添加 markDirty() 辅助方法
- IScene 添加 epochManager 属性
- CommandBuffer.pendingCount 修正为返回实际操作数

文档更新:
- 更新系统调度和查询相关文档
2025-12-15 09:17:00 +08:00

1627 lines
50 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 { PerformanceMonitor } from '../../Utils/PerformanceMonitor';
import { Matcher, type QueryCondition } from '../Utils/Matcher';
import type { Scene } from '../Scene';
import type { ISystemBase } from '../../Types';
import type { QuerySystem } from '../Core/QuerySystem';
import { getSystemInstanceTypeName } from '../Decorators';
import { createLogger } from '../../Utils/Logger';
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
import type { IService } from '../../Core/ServiceContainer';
import { EntityCache } from './EntityCache';
import { CommandBuffer } from '../Core/CommandBuffer';
import type { SystemStage, SystemSchedulingMetadata } from '../Core/SystemScheduler';
import { getSchedulingMetadata } from '../Decorators/SystemScheduling';
/**
* 事件监听器记录
* 只存储引用信息,用于系统销毁时自动清理
*/
interface EventListenerRecord {
eventSystem: TypeSafeEventSystem;
eventType: string;
listenerRef: string;
}
/**
* 实体系统的基类
*
* 用于处理一组符合特定条件的实体。系统是ECS架构中的逻辑处理单元
* 负责对拥有特定组件组合的实体执行业务逻辑。
*
* 支持泛型参数以提供类型安全的组件访问:
*
* @template TComponents - 系统需要的组件类型数组
*
* @example
* ```typescript
* // 传统方式
* class MovementSystem extends EntitySystem {
* constructor() {
* super(Matcher.empty().all(Transform, Velocity));
* }
*
* protected process(entities: readonly Entity[]): void {
* for (const entity of entities) {
* const transform = entity.getComponent(Transform);
* const velocity = entity.getComponent(Velocity);
* transform.position.add(velocity.value);
* }
* }
* }
*
* // 类型安全方式
* class MovementSystem extends EntitySystem<[typeof Transform, typeof Velocity]> {
* constructor() {
* super(Matcher.empty().all(Transform, Velocity));
* }
*
* protected process(entities: readonly Entity[]): void {
* for (const entity of entities) {
* // 类型安全的组件访问
* const [transform, velocity] = this.getComponents(entity);
* transform.position.add(velocity.value);
* }
* }
* }
* ```
*/
export abstract class EntitySystem implements ISystemBase, IService {
private _updateOrder: number;
/**
* 添加顺序,用于 updateOrder 相同时的稳定排序
* Add order for stable sorting when updateOrder is the same
* @internal
*/
private _addOrder: number;
private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null;
private _systemName: string;
private _initialized: boolean;
private _matcher: Matcher;
private _eventListeners: EventListenerRecord[];
private _scene: Scene | null;
private _destroyed: boolean;
protected logger: ReturnType<typeof createLogger>;
/**
* 调度元数据
* Scheduling metadata
*/
protected _schedulingMetadata: SystemSchedulingMetadata;
/**
* 实体ID映射缓存
*/
private _entityIdMap: Map<number, Entity> | null;
private _entityIdMapVersion: number;
/**
* 统一的实体缓存管理器
*/
private _entityCache: EntityCache;
/**
* 命令缓冲区 - 用于延迟执行实体操作
* Command buffer - for deferred entity operations
*
* 在 process() 中使用 commands 可以避免迭代过程中修改实体列表,
* 提高性能并保证迭代安全。命令会在帧末由 Scene 统一执行。
*
* Using commands in process() avoids modifying entity list during iteration,
* improving performance and ensuring iteration safety. Commands are executed by Scene at end of frame.
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* for (const entity of entities) {
* if (shouldDie(entity)) {
* // 延迟执行,不影响当前迭代
* this.commands.destroyEntity(entity);
* }
* }
* }
* ```
*/
protected readonly commands: CommandBuffer = new CommandBuffer();
/**
* 上次处理的 epoch 检查点
* Last processed epoch checkpoint
*
* 用于变更检测,记录上次 forEachChanged 完成时的 epoch。
* Used for change detection, records epoch when forEachChanged last completed.
*/
private _lastProcessEpoch: number = 0;
/**
* 获取系统处理的实体列表
*/
public get entities(): readonly Entity[] {
// 如果在update周期内优先使用帧缓存
const frameCache = this._entityCache.getFrame();
if (frameCache !== null) {
return frameCache;
}
// 否则使用持久缓存
if (!this._entityCache.hasPersistent()) {
this._entityCache.setPersistent(this.queryEntities());
}
return this._entityCache.getPersistent()!;
}
/**
* 获取系统的更新时序
*/
public get updateOrder(): number {
return this._updateOrder;
}
public set updateOrder(value: number) {
this.setUpdateOrder(value);
}
/**
* 获取系统的添加顺序
* Get the add order of the system
* @internal
*/
public get addOrder(): number {
return this._addOrder;
}
/**
* 设置系统的添加顺序(由 Scene 在添加时设置)
* Set the add order of the system (set by Scene when adding)
* @internal
*/
public set addOrder(value: number) {
this._addOrder = 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._updateOrder = 0;
this._addOrder = 0;
this._enabled = true;
this._performanceMonitor = null;
this._systemName = getSystemInstanceTypeName(this);
this._initialized = false;
this._matcher = matcher || Matcher.empty();
this._eventListeners = [];
this._scene = null;
this._destroyed = false;
this._entityIdMap = null;
this._entityIdMapVersion = -1;
// 初始化logger
this.logger = createLogger(this.getLoggerName());
this._entityCache = new EntityCache();
// 初始化调度元数据(优先使用装饰器元数据)
// Initialize scheduling metadata (prefer decorator metadata)
const decoratorMeta = getSchedulingMetadata(this);
this._schedulingMetadata = decoratorMeta
? { ...decoratorMeta }
: {
stage: 'update',
before: [],
after: [],
sets: []
};
}
/**
* 这个系统所属的场景
*/
public get scene(): Scene | null {
return this._scene;
}
public set scene(value: Scene | null) {
this._scene = value;
// 同步更新 CommandBuffer 的场景引用
// Sync CommandBuffer scene reference
this.commands.setScene(value);
}
/**
* 设置性能监控器
*/
public setPerformanceMonitor(monitor: PerformanceMonitor): void {
this._performanceMonitor = monitor;
}
/**
* 获取性能监控器
*/
private getPerformanceMonitor(): PerformanceMonitor {
if (!this._performanceMonitor) {
throw new Error(
`${this._systemName}: PerformanceMonitor未注入请确保在Core.create()之后再添加System到Scene`
);
}
return this._performanceMonitor;
}
/**
* 获取实体匹配器
*/
public get matcher(): Matcher {
return this._matcher;
}
/**
* 设置更新时序
* @param order 更新时序
*/
public setUpdateOrder(order: number): void {
if (this._updateOrder === order) return;
this._updateOrder = order;
this._scene?.markSystemsOrderDirty();
}
// ========================================================================
// 调度配置方法 (Fluent API)
// Scheduling configuration methods (Fluent API)
// ========================================================================
/**
* 设置系统执行阶段
* Set system execution stage
*
* @param stage 执行阶段 | Execution stage
* @returns this (用于链式调用 | for chaining)
*
* @example
* ```typescript
* class MySystem extends EntitySystem {
* constructor() {
* super();
* this.stage('preUpdate');
* }
* }
* ```
*/
public stage(stage: SystemStage): this {
this._schedulingMetadata.stage = stage;
this._scene?.markSystemsOrderDirty();
return this;
}
/**
* 声明此系统在指定系统之前执行
* Declare this system executes before specified systems
*
* @param systems 系统名称列表 | System names
* @returns this (用于链式调用 | for chaining)
*
* @example
* ```typescript
* class MySystem extends EntitySystem {
* constructor() {
* super();
* this.before('RenderSystem');
* }
* }
* ```
*/
public before(...systems: string[]): this {
this._schedulingMetadata.before.push(...systems);
this._scene?.markSystemsOrderDirty();
return this;
}
/**
* 声明此系统在指定系统之后执行
* Declare this system executes after specified systems
*
* @param systems 系统名称列表(可使用 'set:' 前缀指定集合)| System names (use 'set:' prefix for sets)
* @returns this (用于链式调用 | for chaining)
*
* @example
* ```typescript
* class MySystem extends EntitySystem {
* constructor() {
* super();
* this.after('PhysicsSystem', 'set:CoreSystems');
* }
* }
* ```
*/
public after(...systems: string[]): this {
this._schedulingMetadata.after.push(...systems);
this._scene?.markSystemsOrderDirty();
return this;
}
/**
* 将系统加入指定集合
* Add system to specified sets
*
* @param sets 集合名称列表 | Set names
* @returns this (用于链式调用 | for chaining)
*
* @example
* ```typescript
* class MySystem extends EntitySystem {
* constructor() {
* super();
* this.inSet('PhysicsSystems');
* }
* }
* ```
*/
public inSet(...sets: string[]): this {
this._schedulingMetadata.sets.push(...sets);
this._scene?.markSystemsOrderDirty();
return this;
}
/**
* 获取系统的执行阶段
* Get system execution stage
*/
public getStage(): SystemStage {
return this._schedulingMetadata.stage;
}
/**
* 获取系统应该在哪些系统之前执行
* Get systems that this system should execute before
*/
public getBefore(): readonly string[] {
return this._schedulingMetadata.before;
}
/**
* 获取系统应该在哪些系统之后执行
* Get systems that this system should execute after
*/
public getAfter(): readonly string[] {
return this._schedulingMetadata.after;
}
/**
* 获取系统所属的集合
* Get sets that this system belongs to
*/
public getSets(): readonly string[] {
return this._schedulingMetadata.sets;
}
/**
* 系统初始化(框架调用)
*
* 在系统创建时调用。框架内部使用,用户不应直接调用。
*/
public initialize(): void {
// 防止重复初始化 | Prevent re-initialization
if (this._initialized) {
return;
}
this._initialized = true;
// 框架内部初始化:触发一次实体查询,以便正确跟踪现有实体
// Framework initialization: query entities once to track existing entities
if (this.scene) {
// 清理缓存确保初始化时重新查询 | Clear cache to ensure fresh query
this._entityCache.invalidate();
const entities = this.queryEntities();
// 初始化时对已存在的匹配实体触发 onAdded
// Trigger onAdded for existing matching entities during initialization
for (const entity of entities) {
this.onAdded(entity);
}
}
// 调用用户可重写的初始化方法 | Call user-overridable initialization method
this.onInitialize();
}
/**
* 系统初始化回调
*
* 子类可以重写此方法进行初始化操作。
*/
protected onInitialize(): void {
// 子类可以重写此方法进行初始化
}
/**
* 清除实体缓存(内部使用)
* 当Scene中的实体发生变化时调用
*/
public clearEntityCache(): void {
this._entityCache.invalidate();
}
/**
* 完全重置实体跟踪状态
* 清除所有缓存和跟踪的实体,强制下次 update 时重新扫描所有实体并触发 onAdded
* 用于场景重载/预览重置等场景
*/
public resetEntityTracking(): void {
this._entityCache.clearAll();
this._entityIdMap = null;
this._entityIdMapVersion = -1;
}
/**
* 重置系统状态
*
* 当系统从场景中移除时调用,重置初始化状态以便重新添加时能正确初始化。
*
* 注意:此方法由 Scene.removeEntityProcessor 调用,在 unregister触发dispose之后调用。
* dispose 已经调用了 onDestroy 并设置了 _destroyed 标志,所以这里不需要重置该标志。
* 重置 _destroyed 会违反服务容器的语义dispose 后不应重用)。
*/
public reset(): void {
// 如果系统已经被销毁不需要再次调用destroy
if (this._destroyed) {
return;
}
this.scene = null;
this._initialized = false;
this._entityCache.clearAll();
// 清理实体ID映射缓存
this._entityIdMap = null;
this._entityIdMapVersion = -1;
// 清理所有事件监听器并调用销毁回调
this.destroy();
}
/**
* 查询匹配的实体
*/
private queryEntities(): readonly Entity[] {
if (!this.scene?.querySystem || !this._matcher) {
return [];
}
const condition = this._matcher.getCondition();
const querySystem = this.scene.querySystem;
let currentEntities: readonly Entity[] = [];
// matchNothing 条件返回空数组(用于只需要生命周期方法的系统)
if (this._matcher.isNothing()) {
return [];
}
// 空条件返回所有实体
if (this._matcher.isEmpty()) {
currentEntities = querySystem.getAllEntities();
} else if (this.isSingleCondition(condition)) {
// 单一条件优化查询
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
} else {
// 复合查询
currentEntities = this.executeComplexQuery(condition, querySystem);
}
// 检查实体变化并触发回调
this.updateEntityTracking(currentEntities);
return currentEntities;
}
/**
* 检查是否为单一条件查询
*
* 使用位运算优化多条件检测。将每种查询条件映射到不同的位:
* - all: 第0位 (1)
* - any: 第1位 (2)
* - none: 第2位 (4)
* - tag: 第3位 (8)
* - name: 第4位 (16)
* - component: 第5位 (32)
*/
private isSingleCondition(condition: QueryCondition): boolean {
// 使用位OR运算合并所有条件标记
const flags =
(condition.all.length > 0 ? 1 : 0) |
(condition.any.length > 0 ? 2 : 0) |
(condition.none.length > 0 ? 4 : 0) |
(condition.tag !== undefined ? 8 : 0) |
(condition.name !== undefined ? 16 : 0) |
(condition.component !== undefined ? 32 : 0);
// 位运算技巧:如果只有一个位被设置,则 flags & (flags - 1) == 0
// 例如flags=4 (100), flags-1=3 (011), 4&3=0
// 但如果 flags=6 (110), flags-1=5 (101), 6&5=4≠0
return flags !== 0 && (flags & (flags - 1)) === 0;
}
/**
* 执行单一条件查询
*/
private executeSingleConditionQuery(condition: QueryCondition, querySystem: QuerySystem): readonly Entity[] {
// 按标签查询
if (condition.tag !== undefined) {
return querySystem.queryByTag(condition.tag).entities;
}
// 按名称查询
if (condition.name !== undefined) {
return querySystem.queryByName(condition.name).entities;
}
// 单组件查询
if (condition.component !== undefined) {
return querySystem.queryByComponent(condition.component).entities;
}
// 基础组件查询
if (condition.all.length > 0 && condition.any.length === 0 && condition.none.length === 0) {
return querySystem.queryAll(...condition.all).entities;
}
if (condition.all.length === 0 && condition.any.length > 0 && condition.none.length === 0) {
return querySystem.queryAny(...condition.any).entities;
}
if (condition.all.length === 0 && condition.any.length === 0 && condition.none.length > 0) {
return querySystem.queryNone(...condition.none).entities;
}
return [];
}
/**
* 执行复合查询
*/
private executeComplexQueryWithIdSets(condition: QueryCondition, querySystem: QuerySystem): readonly Entity[] {
let resultIds: Set<number> | null = null;
// 1. 应用标签条件作为基础集合
if (condition.tag !== undefined) {
const tagResult = querySystem.queryByTag(condition.tag);
resultIds = this.extractEntityIds(tagResult.entities);
}
// 2. 应用名称条件 (交集)
if (condition.name !== undefined) {
const nameIds = this.extractEntityIds(querySystem.queryByName(condition.name).entities);
resultIds = resultIds ? this.intersectIdSets(resultIds, nameIds) : nameIds;
}
// 3. 应用单组件条件 (交集)
if (condition.component !== undefined) {
const componentIds = this.extractEntityIds(querySystem.queryByComponent(condition.component).entities);
resultIds = resultIds ? this.intersectIdSets(resultIds, componentIds) : componentIds;
}
// 4. 应用all条件 (交集)
if (condition.all.length > 0) {
const allIds = this.extractEntityIds(querySystem.queryAll(...condition.all).entities);
resultIds = resultIds ? this.intersectIdSets(resultIds, allIds) : allIds;
}
// 5. 应用any条件 (交集)
if (condition.any.length > 0) {
const anyIds = this.extractEntityIds(querySystem.queryAny(...condition.any).entities);
resultIds = resultIds ? this.intersectIdSets(resultIds, anyIds) : anyIds;
}
// 6. 应用none条件 (差集)
if (condition.none.length > 0) {
if (!resultIds) {
resultIds = this.extractEntityIds(querySystem.getAllEntities());
}
const noneResult = querySystem.queryAny(...condition.none);
const noneIds = this.extractEntityIds(noneResult.entities);
resultIds = this.differenceIdSets(resultIds, noneIds);
}
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.getAllEntities()) : [];
}
/**
* 提取实体ID集合
*/
private extractEntityIds(entities: readonly Entity[]): Set<number> {
const len = entities.length;
const idSet = new Set<number>();
for (let i = 0; i < len; i = (i + 1) | 0) {
idSet.add(entities[i]!.id | 0);
}
return idSet;
}
/**
* ID集合交集运算
*/
private intersectIdSets(setA: Set<number>, setB: Set<number>): Set<number> {
let smaller: Set<number>, larger: Set<number>;
if (setA.size <= setB.size) {
smaller = setA;
larger = setB;
} else {
smaller = setB;
larger = setA;
}
const result = new Set<number>();
for (const id of smaller) {
if (larger.has(id)) {
result.add(id);
}
}
return result;
}
/**
* ID集合差集运算
*/
private differenceIdSets(setA: Set<number>, setB: Set<number>): Set<number> {
const result = new Set<number>();
for (const id of setA) {
if (!setB.has(id)) {
result.add(id);
}
}
return result;
}
/**
* 获取或构建实体ID映射
*/
private getEntityIdMap(allEntities: readonly Entity[]): Map<number, Entity> {
const currentVersion = this.scene?.querySystem?.version ?? 0;
if (this._entityIdMap !== null && this._entityIdMapVersion === currentVersion) {
return this._entityIdMap;
}
return this.rebuildEntityIdMap(allEntities, currentVersion);
}
/**
* 重建实体ID映射
*/
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
let entityMap = this._entityIdMap;
if (!entityMap) {
entityMap = new Map<number, Entity>();
} else {
entityMap.clear();
}
const len = allEntities.length;
for (let i = 0; i < len; i = (i + 1) | 0) {
const entity = allEntities[i]!;
entityMap.set(entity.id | 0, entity);
}
this._entityIdMap = entityMap;
this._entityIdMapVersion = version;
return entityMap;
}
/**
* 从ID集合构建Entity数组
*/
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
const entityMap = this.getEntityIdMap(allEntities);
const size = idSet.size;
const result = new Array<Entity>(size);
let index = 0;
for (const id of idSet) {
const entity = entityMap.get(id);
if (entity !== undefined) {
result[index] = entity;
index = (index + 1) | 0;
}
}
if (index < size) {
result.length = index;
}
return result;
}
/**
* 执行复合查询
*
* 使用基于ID集合的单次扫描算法进行复杂查询
*/
private executeComplexQuery(condition: QueryCondition, querySystem: QuerySystem): readonly Entity[] {
return this.executeComplexQueryWithIdSets(condition, querySystem);
}
/**
* 更新系统
*/
public update(): void {
if (!this._enabled || !this.onCheckProcessing()) {
return;
}
const monitor = this.getPerformanceMonitor();
const startTime = monitor.startMonitoring(this._systemName);
let entityCount = 0;
try {
this.onBegin();
// 查询实体并存储到帧缓存中
// ReactiveQuery.getEntities() 返回的是安全快照,只在实体变化时才创建新数组
// ReactiveQuery.getEntities() returns a safe snapshot, only creates new array when entities change
const entities = this.queryEntities();
this._entityCache.setFrame(entities);
entityCount = entities.length;
this.process(entities);
} finally {
monitor.endMonitoring(this._systemName, startTime, entityCount);
}
}
/**
* 后期更新系统
*/
public lateUpdate(): void {
if (!this._enabled || !this.onCheckProcessing()) {
return;
}
const monitor = this.getPerformanceMonitor();
const startTime = monitor.startMonitoring(`${this._systemName}_Late`);
let entityCount = 0;
try {
// 重新查询实体以获取最新列表
// 在 update 和 lateUpdate 之间可能有新组件被添加(事件驱动设计)
// Re-query entities to get the latest list
// New components may have been added between update and lateUpdate (event-driven design)
// ReactiveQuery.getEntities() 返回的是安全快照,只在实体变化时才创建新数组
const entities = this.queryEntities();
this._entityCache.setFrame(entities);
entityCount = entities.length;
this.lateProcess(entities);
this.onEnd();
} finally {
monitor.endMonitoring(`${this._systemName}_Late`, startTime, entityCount);
// 清理帧缓存
this._entityCache.clearFrame();
}
}
/**
* 执行命令缓冲区中的所有延迟命令
* Flush all deferred commands in the command buffer
*
* 由 Scene 在帧末自动调用。
* Called automatically by Scene at end of frame.
*
* @returns 执行的命令数量 | Number of commands executed
*/
public flushCommands(): number {
return this.commands.flush();
}
/**
* 在系统处理开始前调用
*
* 子类可以重写此方法进行预处理操作。
*/
protected onBegin(): void {
// 子类可以重写此方法
}
/**
* 处理实体列表
*
* 系统的核心逻辑,子类必须实现此方法来定义具体的处理逻辑。
*
* @param entities 要处理的实体列表
*/
protected process(_entities: readonly Entity[]): void {
// 子类必须实现此方法
}
/**
* 后期处理实体列表
*
* 在主要处理逻辑之后执行,子类可以重写此方法。
*
* @param entities 要处理的实体列表
*/
protected lateProcess(_entities: readonly Entity[]): void {
// 子类可以重写此方法
}
/**
* 系统处理完毕后调用
*
* 子类可以重写此方法进行后处理操作。
*/
protected onEnd(): void {
// 子类可以重写此方法
}
/**
* 检查系统是否需要处理
*
* 在启用系统时有用,但仅偶尔需要处理。
* 这只影响处理,不影响事件或订阅列表。
*
* @returns 如果系统应该处理则为true如果不处理则为false
*/
protected onCheckProcessing(): boolean {
return true;
}
/**
* 获取系统的性能数据
*
* @returns 性能数据或undefined
*/
public getPerformanceData() {
return this.getPerformanceMonitor().getSystemData(this._systemName);
}
/**
* 获取系统的性能统计
*
* @returns 性能统计或undefined
*/
public getPerformanceStats() {
return this.getPerformanceMonitor().getSystemStats(this._systemName);
}
/**
* 重置系统的性能数据
*/
public resetPerformanceData(): void {
this.getPerformanceMonitor().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}`;
}
/**
* 检查实体是否匹配当前系统的查询条件
* Check if an entity matches this system's query condition
*
* @param entity 要检查的实体 / The entity to check
* @returns 是否匹配 / Whether the entity matches
*/
public matchesEntity(entity: Entity): boolean {
if (!this._matcher) {
return false;
}
// nothing 匹配器不匹配任何实体
if (this._matcher.isNothing()) {
return false;
}
// 空匹配器匹配所有实体
if (this._matcher.isEmpty()) {
return true;
}
const condition = this._matcher.getCondition();
// 检查 all 条件
for (const componentType of condition.all) {
if (!entity.hasComponent(componentType)) {
return false;
}
}
// 检查 any 条件
if (condition.any.length > 0) {
let hasAny = false;
for (const componentType of condition.any) {
if (entity.hasComponent(componentType)) {
hasAny = true;
break;
}
}
if (!hasAny) {
return false;
}
}
// 检查 none 条件
for (const componentType of condition.none) {
if (entity.hasComponent(componentType)) {
return false;
}
}
// 检查 tag 条件
if (condition.tag !== undefined && entity.tag !== condition.tag) {
return false;
}
// 检查 name 条件
if (condition.name !== undefined && entity.name !== condition.name) {
return false;
}
// 检查单组件条件
if (condition.component !== undefined && !entity.hasComponent(condition.component)) {
return false;
}
return true;
}
/**
* 检查实体是否正在被此系统跟踪
* Check if an entity is being tracked by this system
*
* @param entity 要检查的实体 / The entity to check
* @returns 是否正在跟踪 / Whether the entity is being tracked
*/
public isTracking(entity: Entity): boolean {
return this._entityCache.isTracked(entity);
}
/**
* 当实体的组件发生变化时由 Scene 调用
*
* 立即检查实体是否匹配并触发 onAdded/onRemoved 回调。
* 这是事件驱动设计的核心:组件变化时立即通知相关系统。
*
* Called by Scene when an entity's components change.
* Immediately checks if the entity matches and triggers onAdded/onRemoved callbacks.
* This is the core of event-driven design: notify relevant systems immediately when components change.
*
* @param entity 组件发生变化的实体 / The entity whose components changed
* @internal 由 Scene.notifyEntityComponentChanged 调用 / Called by Scene.notifyEntityComponentChanged
*/
public handleEntityComponentChanged(entity: Entity): void {
if (!this._matcher || !this._enabled) {
return;
}
const wasTracked = this._entityCache.isTracked(entity);
const nowMatches = this.matchesEntity(entity);
if (!wasTracked && nowMatches) {
// 新匹配:添加跟踪并触发 onAdded | New match: add tracking and trigger onAdded
this._entityCache.addTracked(entity);
this._entityCache.invalidate();
this.onAdded(entity);
} else if (wasTracked && !nowMatches) {
// 不再匹配:移除跟踪并触发 onRemoved | No longer matches: remove tracking and trigger onRemoved
this._entityCache.removeTracked(entity);
this._entityCache.invalidate();
this.onRemoved(entity);
}
}
/**
* 更新实体跟踪,检查新增和移除的实体
*
* 由于采用了事件驱动设计,运行时的 onAdded/onRemoved 已在 handleEntityComponentChanged 中
* 立即触发。此方法不再触发回调,只同步跟踪状态。
*
* With event-driven design, runtime onAdded/onRemoved are triggered immediately in
* handleEntityComponentChanged. This method no longer triggers callbacks, only syncs tracking state.
*/
private updateEntityTracking(currentEntities: readonly Entity[]): void {
const currentSet = new Set(currentEntities);
let hasChanged = false;
// 检查新增的实体 | Check for newly added entities
for (const entity of currentEntities) {
if (!this._entityCache.isTracked(entity)) {
this._entityCache.addTracked(entity);
hasChanged = true;
}
}
// 检查移除的实体 | Check for removed entities
for (const entity of this._entityCache.getTracked()) {
if (!currentSet.has(entity)) {
this._entityCache.removeTracked(entity);
hasChanged = true;
}
}
// 如果实体发生了变化,使缓存失效 | If entities changed, invalidate cache
if (hasChanged) {
this._entityCache.invalidate();
}
}
/**
* 当实体被添加到系统时调用
*
* 子类可以重写此方法来处理实体添加事件。
*
* @param entity 被添加的实体
*/
protected onAdded(_entity: Entity): void {
// 子类可以重写此方法
}
/**
* 当实体从系统中移除时调用
*
* 子类可以重写此方法来处理实体移除事件。
*
* @param entity 被移除的实体
*/
protected onRemoved(_entity: Entity): void {
// 子类可以重写此方法
}
/**
* 释放系统资源
*
* 实现IService接口要求的dispose方法。
* 当系统从Scene中移除或Scene销毁时调用。
*
* 默认行为:
* - 移除所有事件监听器
* - 调用 onDestroy 回调(仅首次)
* - 清空所有缓存
* - 重置初始化状态
*
* 子类可以重写此方法来清理自定义资源但应该调用super.dispose()。
*/
public dispose(): void {
// 防止重复销毁
if (this._destroyed) {
return;
}
// 移除所有事件监听器
this.cleanupManualEventListeners();
// 调用用户销毁回调
this.onDestroy();
// 清空所有缓存
this._entityCache.clearAll();
this._entityIdMap = null;
// 清理命令缓冲区
// Clear command buffer
this.commands.dispose();
// 重置状态
this._initialized = false;
this._scene = null;
this._destroyed = true;
this.logger.debug(`System ${this._systemName} disposed`);
}
/**
* 添加事件监听器
*
* 推荐使用此方法而不是直接调用eventSystem.on()
* 这样可以确保系统移除时自动清理监听器,避免内存泄漏。
*
* @param eventType 事件类型
* @param handler 事件处理函数
* @param config 监听器配置
* @returns 监听器引用ID可用于手动移除监听器
*/
protected addEventListener<T>(
eventType: string,
handler: EventHandler<T>,
config?: EventListenerConfig
): string | null {
if (!this.scene?.eventSystem) {
this.logger.warn(`${this.systemName}: 无法添加事件监听器scene.eventSystem 不可用`);
return null;
}
const listenerRef = this.scene.eventSystem.on(eventType, handler, config);
// 跟踪监听器以便后续清理
if (listenerRef) {
this._eventListeners.push({
eventSystem: this.scene.eventSystem,
eventType,
listenerRef
});
}
return listenerRef;
}
/**
* 移除特定的事件监听器
*
* @param eventType 事件类型
* @param listenerRef 监听器引用ID由 addEventListener 返回)
*/
protected removeEventListener(eventType: string, listenerRef: string): void {
const listenerIndex = this._eventListeners.findIndex(
(listener) => listener.eventType === eventType && listener.listenerRef === listenerRef
);
if (listenerIndex >= 0) {
const listener = this._eventListeners[listenerIndex];
if (!listener) return;
// 从事件系统中移除
listener.eventSystem.off(eventType, listener.listenerRef);
// 从跟踪列表中移除
this._eventListeners.splice(listenerIndex, 1);
}
}
/**
* 清理手动添加的事件监听器
*/
private cleanupManualEventListeners(): void {
for (const listener of this._eventListeners) {
try {
listener.eventSystem.off(listener.eventType, listener.listenerRef);
} catch (error) {
this.logger.warn(`${this.systemName}: 移除事件监听器失败 "${listener.eventType}"`, error);
}
}
// 清空跟踪列表
this._eventListeners.length = 0;
}
/**
* 框架内部销毁方法
* 由框架调用,处理系统的完整销毁流程
*/
public destroy(): void {
// 防止重复销毁
if (this._destroyed) {
return;
}
this.cleanupManualEventListeners();
this._destroyed = true;
this.onDestroy();
}
/**
* 获取Logger名称
* 默认返回类的构造函数名称, 子类可以重写此方法来自定义logger名称
*/
protected getLoggerName(): string {
return getSystemInstanceTypeName(this);
}
/**
* 用户销毁回调
*
* 当系统从场景中移除时调用,子类可以重写此方法进行清理操作。
* 注意:事件监听器会被框架自动清理,无需手动处理。
*/
protected onDestroy(): void {
// 子类可以重写此方法进行清理操作
}
/**
* 类型安全地获取单个组件
*
* 相比Entity.getComponent此方法保证返回非空值
* 如果组件不存在会抛出错误而不是返回null
*
* @param entity 实体
* @param componentType 组件类型
* @returns 组件实例(保证非空)
* @throws 如果组件不存在则抛出错误
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* for (const entity of entities) {
* const transform = this.requireComponent(entity, Transform);
* // transform 保证非空,类型为 Transform
* }
* }
* ```
*/
protected requireComponent<T extends ComponentConstructor>(entity: Entity, componentType: T): ComponentInstance<T> {
const component = entity.getComponent(componentType);
if (!component) {
throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`);
}
return component as ComponentInstance<T>;
}
/**
* 批量获取实体的所有必需组件
*
* 根据泛型参数TComponents推断返回类型
* 返回一个元组,包含所有组件实例
*
* @param entity 实体
* @param components 组件类型数组
* @returns 组件实例元组
*
* @example
* ```typescript
* class MySystem extends EntitySystem<[typeof Position, typeof Velocity]> {
* protected process(entities: readonly Entity[]): void {
* for (const entity of entities) {
* const [pos, vel] = this.getComponents(entity, Position, Velocity);
* // pos: Position, vel: Velocity (自动类型推断)
* pos.x += vel.x;
* }
* }
* }
* ```
*/
protected getComponents<T extends readonly ComponentConstructor[]>(
entity: Entity,
...components: T
): { [K in keyof T]: ComponentInstance<T[K]> } {
return components.map((type) => this.requireComponent(entity, type)) as {
[K in keyof T]: ComponentInstance<T[K]>;
};
}
/**
* 遍历实体并处理每个实体
*
* 提供更简洁的语法糖,避免手动遍历
*
* @param entities 实体列表
* @param processor 处理函数
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* this.forEach(entities, (entity) => {
* const transform = this.requireComponent(entity, Transform);
* transform.position.y -= 9.8 * Time.deltaTime;
* });
* }
* ```
*/
protected forEach(entities: readonly Entity[], processor: (entity: Entity, index: number) => void): void {
for (let i = 0; i < entities.length; i++) {
processor(entities[i]!, i);
}
}
/**
* 过滤实体
*
* @param entities 实体列表
* @param predicate 过滤条件
* @returns 过滤后的实体数组
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const activeEntities = this.filterEntities(entities, (entity) => {
* const health = this.requireComponent(entity, Health);
* return health.value > 0;
* });
* }
* ```
*/
protected filterEntities(
entities: readonly Entity[],
predicate: (entity: Entity, index: number) => boolean
): Entity[] {
return Array.from(entities).filter(predicate);
}
/**
* 映射实体到另一种类型
*
* @param entities 实体列表
* @param mapper 映射函数
* @returns 映射后的结果数组
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const positions = this.mapEntities(entities, (entity) => {
* const transform = this.requireComponent(entity, Transform);
* return transform.position;
* });
* }
* ```
*/
protected mapEntities<R>(entities: readonly Entity[], mapper: (entity: Entity, index: number) => R): R[] {
return Array.from(entities).map(mapper);
}
/**
* 查找第一个满足条件的实体
*
* @param entities 实体列表
* @param predicate 查找条件
* @returns 第一个满足条件的实体或undefined
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const player = this.findEntity(entities, (entity) =>
* entity.hasComponent(PlayerTag)
* );
* }
* ```
*/
protected findEntity(
entities: readonly Entity[],
predicate: (entity: Entity, index: number) => boolean
): Entity | undefined {
for (let i = 0; i < entities.length; i++) {
if (predicate(entities[i]!, i)) {
return entities[i];
}
}
return undefined;
}
/**
* 检查是否存在满足条件的实体
*
* @param entities 实体列表
* @param predicate 检查条件
* @returns 是否存在满足条件的实体
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const hasLowHealth = this.someEntity(entities, (entity) => {
* const health = this.requireComponent(entity, Health);
* return health.value < 20;
* });
* }
* ```
*/
protected someEntity(entities: readonly Entity[], predicate: (entity: Entity, index: number) => boolean): boolean {
for (let i = 0; i < entities.length; i++) {
if (predicate(entities[i]!, i)) {
return true;
}
}
return false;
}
/**
* 检查是否所有实体都满足条件
*
* @param entities 实体列表
* @param predicate 检查条件
* @returns 是否所有实体都满足条件
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const allHealthy = this.everyEntity(entities, (entity) => {
* const health = this.requireComponent(entity, Health);
* return health.value > 50;
* });
* }
* ```
*/
protected everyEntity(entities: readonly Entity[], predicate: (entity: Entity, index: number) => boolean): boolean {
for (let i = 0; i < entities.length; i++) {
if (!predicate(entities[i]!, i)) {
return false;
}
}
return true;
}
// ========================================================================
// 变更检测方法 (Change Detection Methods)
// ========================================================================
/**
* 获取上次处理的 epoch 检查点
* Get the last processed epoch checkpoint
*
* @returns 上次处理完成时的 epoch | Epoch when last processing completed
*/
protected get lastProcessEpoch(): number {
return this._lastProcessEpoch;
}
/**
* 获取当前 epoch
* Get the current epoch
*
* @returns 当前的 epoch 值,如果 scene 不可用则返回 0 | Current epoch value, or 0 if scene unavailable
*/
protected get currentEpoch(): number {
return this._scene?.epochManager?.current ?? 0;
}
/**
* 保存当前 epoch 作为检查点
* Save current epoch as checkpoint
*
* 调用此方法后,下次 forEachChanged 将只处理此时间点之后变更的组件。
* After calling this, next forEachChanged will only process components changed after this point.
*/
protected saveEpoch(): void {
this._lastProcessEpoch = this.currentEpoch;
}
/**
* 遍历有变更组件的实体
* Iterate entities with changed components
*
* 只处理自上次 saveEpoch() 或指定 epoch 以来组件发生变更的实体。
* 处理完成后自动更新 lastProcessEpoch。
*
* Only processes entities whose components changed since last saveEpoch() or specified epoch.
* Automatically updates lastProcessEpoch after processing.
*
* @param entities 实体列表 | Entity list
* @param componentTypes 要检查变更的组件类型 | Component types to check for changes
* @param processor 处理函数 | Processor function
* @param sinceEpoch 可选的起始 epoch默认使用 lastProcessEpoch | Optional starting epoch, defaults to lastProcessEpoch
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* // 只处理 Velocity 组件发生变更的实体
* this.forEachChanged(entities, [Velocity], (entity) => {
* const vel = this.requireComponent(entity, Velocity);
* // 只有 velocity 改变时才重新计算
* this.updatePhysics(entity, vel);
* });
* }
* ```
*/
protected forEachChanged<T extends ComponentConstructor[]>(
entities: readonly Entity[],
componentTypes: T,
processor: (entity: Entity, index: number) => void,
sinceEpoch?: number
): void {
const checkEpoch = sinceEpoch ?? this._lastProcessEpoch;
for (let i = 0; i < entities.length; i++) {
const entity = entities[i]!;
let hasChanged = false;
// 检查任意指定组件是否发生变更
// Check if any specified component has changed
for (const componentType of componentTypes) {
const component = entity.getComponent(componentType);
if (component && component.lastWriteEpoch > checkEpoch) {
hasChanged = true;
break;
}
}
if (hasChanged) {
processor(entity, i);
}
}
// 自动更新检查点
// Automatically update checkpoint
this._lastProcessEpoch = this.currentEpoch;
}
/**
* 过滤出有变更组件的实体
* Filter entities with changed components
*
* @param entities 实体列表 | Entity list
* @param componentTypes 要检查变更的组件类型 | Component types to check for changes
* @param sinceEpoch 可选的起始 epoch | Optional starting epoch
* @returns 有变更的实体数组 | Array of entities with changes
*
* @example
* ```typescript
* protected process(entities: readonly Entity[]): void {
* const changedEntities = this.filterChanged(entities, [Position, Velocity]);
* for (const entity of changedEntities) {
* // 处理位置或速度变化的实体
* }
* this.saveEpoch();
* }
* ```
*/
protected filterChanged<T extends ComponentConstructor[]>(
entities: readonly Entity[],
componentTypes: T,
sinceEpoch?: number
): Entity[] {
const checkEpoch = sinceEpoch ?? this._lastProcessEpoch;
const result: Entity[] = [];
for (let i = 0; i < entities.length; i++) {
const entity = entities[i]!;
for (const componentType of componentTypes) {
const component = entity.getComponent(componentType);
if (component && component.lastWriteEpoch > checkEpoch) {
result.push(entity);
break;
}
}
}
return result;
}
/**
* 检查实体的指定组件是否发生变更
* Check if entity's specified components have changed
*
* @param entity 实体 | Entity
* @param componentTypes 要检查的组件类型 | Component types to check
* @param sinceEpoch 可选的起始 epoch | Optional starting epoch
* @returns 是否有变更 | Whether there are changes
*/
protected hasChanged<T extends ComponentConstructor[]>(
entity: Entity,
componentTypes: T,
sinceEpoch?: number
): boolean {
const checkEpoch = sinceEpoch ?? this._lastProcessEpoch;
for (const componentType of componentTypes) {
const component = entity.getComponent(componentType);
if (component && component.lastWriteEpoch > checkEpoch) {
return true;
}
}
return false;
}
}