移除废弃的文件

This commit is contained in:
YHH
2025-09-30 20:44:08 +08:00
parent ce7b731bcf
commit 51debede52
6 changed files with 0 additions and 1080 deletions

View File

@@ -1,27 +0,0 @@
/**
* 可更新接口
* @deprecated 不符合ECS架构规范建议使用EntitySystem来处理更新逻辑而非在组件中实现
*/
export interface IUpdatable {
enabled: boolean;
updateOrder: number;
update(): void;
}
/**
* 用于比较组件更新排序的比较器
*/
export class IUpdatableComparer {
public compare(a: IUpdatable, b: IUpdatable): number {
return a.updateOrder - b.updateOrder;
}
}
/**
* 检查对象是否实现了IUpdatable接口
* @param props 要检查的对象
* @returns 如果实现了IUpdatable接口返回true否则返回false
*/
export function isIUpdatable(props: any): props is IUpdatable {
return typeof (props as IUpdatable)['update'] !== 'undefined';
}

View File

@@ -1,65 +0,0 @@
import type { Scene } from '../Scene';
/**
* 场景组件基类
* 附加到场景的组件,用于实现场景级别的功能
*/
export class SceneComponent {
/** 组件所属的场景 */
public scene!: Scene;
/** 更新顺序 */
public updateOrder: number = 0;
/** 是否启用 */
private _enabled: boolean = true;
/** 获取是否启用 */
public get enabled(): boolean {
return this._enabled;
}
/** 设置是否启用 */
public set enabled(value: boolean) {
if (this._enabled !== value) {
this._enabled = value;
if (this._enabled) {
this.onEnabled();
} else {
this.onDisabled();
}
}
}
/**
* 当组件启用时调用
*/
public onEnabled(): void {
}
/**
* 当组件禁用时调用
*/
public onDisabled(): void {
}
/**
* 当组件从场景中移除时调用
*/
public onRemovedFromScene(): void {
}
/**
* 每帧更新
* @deprecated 不符合ECS架构规范建议使用EntitySystem来处理场景级更新逻辑
*/
public update(): void {
}
/**
* 比较组件的更新顺序
* @param other 其他组件
* @returns 比较结果
*/
public compare(other: SceneComponent): number {
return this.updateOrder - other.updateOrder;
}
}

View File

@@ -1,181 +0,0 @@
import { Entity } from '../Entity';
import { ComponentType } from './ComponentStorage';
import { ComponentSparseSet } from '../Utils/ComponentSparseSet';
/**
* 索引统计信息
*/
export interface IndexStats {
/** 索引大小 */
size: number;
/** 内存使用量(字节) */
memoryUsage: number;
/** 查询次数 */
queryCount: number;
/** 平均查询时间(毫秒) */
avgQueryTime: number;
/** 最后更新时间 */
lastUpdated: number;
}
/**
* 组件索引接口
*/
export interface IComponentIndex {
/** 添加实体到索引 */
addEntity(entity: Entity): void;
/** 从索引中移除实体 */
removeEntity(entity: Entity): void;
/** 查询包含指定组件的实体 */
query(componentType: ComponentType): Set<Entity>;
/** 批量查询多个组件 */
queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set<Entity>;
/** 清空索引 */
clear(): void;
/** 获取索引统计信息 */
getStats(): IndexStats;
}
/**
* 通用组件索引实现
*
* 基于Sparse Set算法
* - O(1)的实体添加、删除、查找
* - 高效的位运算查询
* - 内存紧凑的存储结构
* - 缓存友好的遍历性能
*/
export class ComponentIndex implements IComponentIndex {
/**
* 组件稀疏集合
*
* 核心存储结构,处理所有实体和组件的索引操作。
*/
private _sparseSet: ComponentSparseSet;
// 性能统计
private _queryCount = 0;
private _totalQueryTime = 0;
private _lastUpdated = Date.now();
constructor() {
this._sparseSet = new ComponentSparseSet();
}
public addEntity(entity: Entity): void {
this._sparseSet.addEntity(entity);
this._lastUpdated = Date.now();
}
public removeEntity(entity: Entity): void {
this._sparseSet.removeEntity(entity);
this._lastUpdated = Date.now();
}
public query(componentType: ComponentType): Set<Entity> {
const startTime = performance.now();
const result = this._sparseSet.queryByComponent(componentType);
this._queryCount++;
this._totalQueryTime += performance.now() - startTime;
return result;
}
public queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set<Entity> {
const startTime = performance.now();
let result: Set<Entity>;
if (componentTypes.length === 0) {
result = new Set();
} else if (componentTypes.length === 1) {
result = this.query(componentTypes[0]);
} else if (operation === 'AND') {
result = this._sparseSet.queryMultipleAnd(componentTypes);
} else {
result = this._sparseSet.queryMultipleOr(componentTypes);
}
this._queryCount++;
this._totalQueryTime += performance.now() - startTime;
return result;
}
public clear(): void {
this._sparseSet.clear();
this._lastUpdated = Date.now();
}
public getStats(): IndexStats {
const memoryStats = this._sparseSet.getMemoryStats();
return {
size: this._sparseSet.size,
memoryUsage: memoryStats.totalMemory,
queryCount: this._queryCount,
avgQueryTime: this._queryCount > 0 ? this._totalQueryTime / this._queryCount : 0,
lastUpdated: this._lastUpdated
};
}
}
/**
* 组件索引管理器
*
* 使用统一的组件索引实现,自动优化查询性能。
*/
export class ComponentIndexManager {
private _index: ComponentIndex;
constructor() {
this._index = new ComponentIndex();
}
/**
* 添加实体到索引
*/
public addEntity(entity: Entity): void {
this._index.addEntity(entity);
}
/**
* 从索引中移除实体
*/
public removeEntity(entity: Entity): void {
this._index.removeEntity(entity);
}
/**
* 查询包含指定组件的实体
*/
public query(componentType: ComponentType): Set<Entity> {
return this._index.query(componentType);
}
/**
* 批量查询多个组件
*/
public queryMultiple(componentTypes: ComponentType[], operation: 'AND' | 'OR'): Set<Entity> {
return this._index.queryMultiple(componentTypes, operation);
}
/**
* 获取索引统计信息
*/
public getStats(): IndexStats {
return this._index.getStats();
}
/**
* 清空索引
*/
public clear(): void {
this._index.clear();
}
}

View File

@@ -1,377 +0,0 @@
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType } from './ComponentStorage';
import { createLogger } from '../../Utils/Logger';
/**
* 脏标记类型
*/
export enum DirtyFlag {
/** 组件数据已修改 */
COMPONENT_MODIFIED = 1 << 0,
/** 组件已添加 */
COMPONENT_ADDED = 1 << 1,
/** 组件已移除 */
COMPONENT_REMOVED = 1 << 2,
/** 实体位置已改变 */
TRANSFORM_CHANGED = 1 << 3,
/** 实体状态已改变 */
STATE_CHANGED = 1 << 4,
/** 自定义标记1 */
CUSTOM_1 = 1 << 8,
/** 自定义标记2 */
CUSTOM_2 = 1 << 9,
/** 自定义标记3 */
CUSTOM_3 = 1 << 10,
/** 所有标记 */
ALL = 0xFFFFFFFF
}
/**
* 脏标记数据
*/
export interface DirtyData {
/** 实体引用 */
entity: Entity;
/** 脏标记位 */
flags: number;
/** 修改的组件类型列表 */
modifiedComponents: Set<ComponentType>;
/** 标记时间戳 */
timestamp: number;
/** 帧编号 */
frameNumber: number;
}
/**
* 脏标记监听器
*/
export interface DirtyListener {
/** 感兴趣的标记类型 */
flags: number;
/** 回调函数 */
callback: (dirtyData: DirtyData) => void;
/** 监听器优先级(数字越小优先级越高) */
priority?: number;
}
/**
* 脏标记统计信息
*/
export interface DirtyStats {
/** 当前脏实体数量 */
dirtyEntityCount: number;
/** 总标记次数 */
totalMarkings: number;
/** 总清理次数 */
totalCleanups: number;
/** 监听器数量 */
listenerCount: number;
/** 平均每帧脏实体数量 */
avgDirtyPerFrame: number;
/** 内存使用量估算 */
estimatedMemoryUsage: number;
}
/**
* 脏标记追踪系统
*
* 提供高效的组件和实体变更追踪,避免不必要的计算和更新。
* 支持细粒度的脏标记和批量处理机制。
*
* @example
* ```typescript
* const dirtySystem = new DirtyTrackingSystem();
*
* // 标记实体的位置组件已修改
* dirtySystem.markDirty(entity, DirtyFlag.TRANSFORM_CHANGED, [PositionComponent]);
*
* // 监听位置变化
* dirtySystem.addListener({
* flags: DirtyFlag.TRANSFORM_CHANGED,
* callback: (data) => {
* logger.debug('Entity position changed:', data.entity.name);
* }
* });
*
* // 处理所有脏标记
* dirtySystem.processDirtyEntities();
* ```
*/
export class DirtyTrackingSystem {
private static readonly _logger = createLogger('DirtyTrackingSystem');
/** 脏实体映射表 */
private _dirtyEntities = new Map<Entity, DirtyData>();
/** 脏标记监听器 */
private _listeners: DirtyListener[] = [];
/** 性能统计 */
private _stats = {
totalMarkings: 0,
totalCleanups: 0,
frameCount: 0,
totalDirtyPerFrame: 0
};
/** 当前帧编号 */
private _currentFrame = 0;
private _batchSize = 100;
private _maxProcessingTime = 16;
/** 延迟处理队列 */
private _processingQueue: DirtyData[] = [];
private _isProcessing = false;
/**
* 标记实体为脏状态
*
* @param entity 要标记的实体
* @param flags 脏标记位
* @param modifiedComponents 修改的组件类型列表
*/
public markDirty(entity: Entity, flags: DirtyFlag, modifiedComponents: ComponentType[] = []): void {
this._stats.totalMarkings++;
let dirtyData = this._dirtyEntities.get(entity);
if (!dirtyData) {
dirtyData = {
entity,
flags: 0,
modifiedComponents: new Set(),
timestamp: performance.now(),
frameNumber: this._currentFrame
};
this._dirtyEntities.set(entity, dirtyData);
}
dirtyData.flags |= flags;
dirtyData.timestamp = performance.now();
dirtyData.frameNumber = this._currentFrame;
for (const componentType of modifiedComponents) {
dirtyData.modifiedComponents.add(componentType);
}
this.notifyListeners(dirtyData, flags);
}
/**
* 检查实体是否有指定的脏标记
*
* @param entity 要检查的实体
* @param flags 要检查的标记位
* @returns 是否有指定的脏标记
*/
public isDirty(entity: Entity, flags: DirtyFlag = DirtyFlag.ALL): boolean {
const dirtyData = this._dirtyEntities.get(entity);
return dirtyData ? (dirtyData.flags & flags) !== 0 : false;
}
/**
* 清除实体的脏标记
*
* @param entity 要清除的实体
* @param flags 要清除的标记位,默认清除所有
*/
public clearDirty(entity: Entity, flags: DirtyFlag = DirtyFlag.ALL): void {
const dirtyData = this._dirtyEntities.get(entity);
if (!dirtyData) return;
if (flags === DirtyFlag.ALL) {
this._dirtyEntities.delete(entity);
} else {
dirtyData.flags &= ~flags;
if (dirtyData.flags === 0) {
this._dirtyEntities.delete(entity);
}
}
this._stats.totalCleanups++;
}
/**
* 获取所有脏实体
*
* @param flags 过滤标记位,只返回包含指定标记的实体
* @returns 脏实体数据数组
*/
public getDirtyEntities(flags: DirtyFlag = DirtyFlag.ALL): DirtyData[] {
const result: DirtyData[] = [];
for (const dirtyData of this._dirtyEntities.values()) {
if ((dirtyData.flags & flags) !== 0) {
result.push(dirtyData);
}
}
return result;
}
/**
* 批量处理脏实体
*
* 使用时间分片的方式处理脏实体,避免单帧卡顿
*/
public processDirtyEntities(): void {
if (this._isProcessing) return;
this._isProcessing = true;
const startTime = performance.now();
if (this._processingQueue.length === 0) {
this._processingQueue.push(...this._dirtyEntities.values());
}
let processed = 0;
while (this._processingQueue.length > 0 && processed < this._batchSize) {
const elapsed = performance.now() - startTime;
if (elapsed > this._maxProcessingTime) {
break;
}
const dirtyData = this._processingQueue.shift()!;
this.processEntity(dirtyData);
processed++;
}
if (this._processingQueue.length === 0) {
this._isProcessing = false;
this.onFrameEnd();
}
}
/**
* 添加脏标记监听器
*
* @param listener 监听器配置
*/
public addListener(listener: DirtyListener): void {
this._listeners.push(listener);
this._listeners.sort((a, b) => (a.priority || 100) - (b.priority || 100));
}
/**
* 移除脏标记监听器
*
* @param callback 要移除的回调函数
*/
public removeListener(callback: (dirtyData: DirtyData) => void): void {
const index = this._listeners.findIndex(l => l.callback === callback);
if (index !== -1) {
this._listeners.splice(index, 1);
}
}
/**
* 开始新的帧
*/
public beginFrame(): void {
this._currentFrame++;
}
/**
* 结束当前帧
*/
public endFrame(): void {
if (!this._isProcessing) {
this.processDirtyEntities();
}
}
/**
* 获取统计信息
*/
public getStats(): DirtyStats {
return {
dirtyEntityCount: this._dirtyEntities.size,
totalMarkings: this._stats.totalMarkings,
totalCleanups: this._stats.totalCleanups,
listenerCount: this._listeners.length,
avgDirtyPerFrame: this._stats.frameCount > 0 ?
this._stats.totalDirtyPerFrame / this._stats.frameCount : 0,
estimatedMemoryUsage: this.estimateMemoryUsage()
};
}
/**
* 清空所有脏标记和统计信息
*/
public clear(): void {
this._dirtyEntities.clear();
this._processingQueue.length = 0;
this._isProcessing = false;
this._stats = {
totalMarkings: 0,
totalCleanups: 0,
frameCount: 0,
totalDirtyPerFrame: 0
};
}
/**
* 配置批量处理参数
*
* @param batchSize 每次处理的最大实体数量
* @param maxProcessingTime 每帧最大处理时间(毫秒)
*/
public configureBatchProcessing(batchSize: number, maxProcessingTime: number): void {
this._batchSize = batchSize;
this._maxProcessingTime = maxProcessingTime;
}
/**
* 处理单个脏实体
*/
private processEntity(dirtyData: DirtyData): void {
for (const listener of this._listeners) {
if ((dirtyData.flags & listener.flags) !== 0) {
try {
listener.callback(dirtyData);
} catch (error) {
DirtyTrackingSystem._logger.error('脏数据监听器错误:', error);
}
}
}
this.clearDirty(dirtyData.entity);
}
/**
* 通知监听器
*/
private notifyListeners(dirtyData: DirtyData, newFlags: DirtyFlag): void {
for (const listener of this._listeners) {
if ((newFlags & listener.flags) !== 0) {
try {
listener.callback(dirtyData);
} catch (error) {
DirtyTrackingSystem._logger.error('脏数据监听器通知错误:', error);
}
}
}
}
/**
* 帧结束时的统计更新
*/
private onFrameEnd(): void {
this._stats.frameCount++;
this._stats.totalDirtyPerFrame += this._dirtyEntities.size;
}
/**
* 估算内存使用量
*/
private estimateMemoryUsage(): number {
let usage = 0;
usage += this._dirtyEntities.size * 100;
usage += this._listeners.length * 50;
usage += this._processingQueue.length * 8;
return usage;
}
}

View File

@@ -1,125 +0,0 @@
import { Component } from '../../ECS/Component';
import { getComponentInstanceTypeName } from '../../ECS/Decorators';
/**
* 调试数据格式化工具
*/
export class DebugDataFormatter {
/**
* 格式化属性值
*/
public static formatPropertyValue(value: any, depth: number = 0): any {
// 防止无限递归,限制最大深度
if (depth > 5) {
return value?.toString() || 'null';
}
if (typeof value === 'object' && value !== null) {
if (Array.isArray(value)) {
// 对于数组,总是返回完整数组,让前端决定如何显示
return value.map(item => this.formatPropertyValue(item, depth + 1));
} else {
// 通用对象处理:提取所有可枚举属性,不限制数量
try {
const keys = Object.keys(value);
if (keys.length === 0) {
return {};
}
const result: any = {};
keys.forEach(key => {
const propValue = value[key];
// 避免循环引用和函数属性
if (propValue !== value && typeof propValue !== 'function') {
try {
result[key] = this.formatPropertyValue(propValue, depth + 1);
} catch (error) {
// 如果属性访问失败,记录错误信息
result[key] = `[访问失败: ${error instanceof Error ? error.message : String(error)}]`;
}
}
});
return result;
} catch (error) {
return `[对象解析失败: ${error instanceof Error ? error.message : String(error)}]`;
}
}
}
return value;
}
/**
* 提取组件详细信息
*/
public static extractComponentDetails(components: Component[]): Array<{
typeName: string;
properties: Record<string, any>;
}> {
return components.map((component: Component) => {
const componentDetail = {
typeName: getComponentInstanceTypeName(component),
properties: {} as Record<string, any>
};
// 安全地提取组件属性
try {
const propertyKeys = Object.keys(component);
propertyKeys.forEach(propertyKey => {
// 跳过私有属性和实体引用,避免循环引用
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
const propertyValue = (component as any)[propertyKey];
if (propertyValue !== undefined && propertyValue !== null) {
componentDetail.properties[propertyKey] = this.formatPropertyValue(propertyValue);
}
}
});
} catch (error) {
componentDetail.properties['_extractionError'] = '属性提取失败';
}
return componentDetail;
});
}
/**
* 计算对象大小
*/
public static calculateObjectSize(obj: any, excludeKeys: string[] = []): number {
if (!obj || typeof obj !== 'object') return 0;
let size = 0;
const visited = new WeakSet();
const calculate = (item: any): number => {
if (!item || typeof item !== 'object' || visited.has(item)) return 0;
visited.add(item);
let itemSize = 0;
try {
for (const key in item) {
if (excludeKeys.includes(key)) continue;
const value = item[key];
itemSize += key.length * 2; // key size
if (typeof value === 'string') {
itemSize += value.length * 2;
} else if (typeof value === 'number') {
itemSize += 8;
} else if (typeof value === 'boolean') {
itemSize += 4;
} else if (typeof value === 'object' && value !== null) {
itemSize += calculate(value);
}
}
} catch (error) {
// 忽略无法访问的属性
}
return itemSize;
};
return calculate(obj);
}
}

View File

@@ -1,305 +0,0 @@
import { ComponentIndex } from '../../../src/ECS/Core/ComponentIndex';
import { Entity } from '../../../src/ECS/Entity';
import { Component } from '../../../src/ECS/Component';
// 测试组件类
class TransformComponent extends Component {
constructor(public x: number = 0, public y: number = 0, public rotation: number = 0) {
super();
}
}
class PhysicsComponent extends Component {
constructor(public mass: number = 1, public friction: number = 0.1) {
super();
}
}
class AudioComponent extends Component {
constructor(public volume: number = 1.0, public muted: boolean = false) {
super();
}
}
class GraphicsComponent extends Component {
constructor(public color: string = '#ffffff', public alpha: number = 1.0) {
super();
}
}
describe('ComponentIndex with SparseSet', () => {
let componentIndex: ComponentIndex;
let entities: Entity[];
beforeEach(() => {
componentIndex = new ComponentIndex();
entities = [];
// 创建测试实体
for (let i = 0; i < 5; i++) {
const entity = new Entity(`testEntity${i}`, i);
entities.push(entity);
}
// entity0: Transform
entities[0].addComponent(new TransformComponent(10, 20, 30));
// entity1: Transform + Physics
entities[1].addComponent(new TransformComponent(40, 50, 60));
entities[1].addComponent(new PhysicsComponent(2.0, 0.2));
// entity2: Physics + Audio
entities[2].addComponent(new PhysicsComponent(3.0, 0.3));
entities[2].addComponent(new AudioComponent(0.8, false));
// entity3: Transform + Physics + Audio
entities[3].addComponent(new TransformComponent(70, 80, 90));
entities[3].addComponent(new PhysicsComponent(4.0, 0.4));
entities[3].addComponent(new AudioComponent(0.6, true));
// entity4: Graphics
entities[4].addComponent(new GraphicsComponent('#ff0000', 0.5));
// 添加所有实体到索引
entities.forEach(entity => componentIndex.addEntity(entity));
});
describe('基本索引操作', () => {
it('应该正确添加实体到索引', () => {
const stats = componentIndex.getStats();
expect(stats.size).toBe(5);
});
it('应该能移除实体', () => {
componentIndex.removeEntity(entities[0]);
const stats = componentIndex.getStats();
expect(stats.size).toBe(4);
const transformEntities = componentIndex.query(TransformComponent);
expect(transformEntities.has(entities[0])).toBe(false);
});
it('应该能清空索引', () => {
componentIndex.clear();
const stats = componentIndex.getStats();
expect(stats.size).toBe(0);
});
});
describe('单组件查询', () => {
it('应该能查询Transform组件', () => {
const result = componentIndex.query(TransformComponent);
expect(result.size).toBe(3);
expect(result.has(entities[0])).toBe(true);
expect(result.has(entities[1])).toBe(true);
expect(result.has(entities[3])).toBe(true);
});
it('应该能查询Physics组件', () => {
const result = componentIndex.query(PhysicsComponent);
expect(result.size).toBe(3);
expect(result.has(entities[1])).toBe(true);
expect(result.has(entities[2])).toBe(true);
expect(result.has(entities[3])).toBe(true);
});
it('应该能查询Audio组件', () => {
const result = componentIndex.query(AudioComponent);
expect(result.size).toBe(2);
expect(result.has(entities[2])).toBe(true);
expect(result.has(entities[3])).toBe(true);
});
it('应该能查询Graphics组件', () => {
const result = componentIndex.query(GraphicsComponent);
expect(result.size).toBe(1);
expect(result.has(entities[4])).toBe(true);
});
});
describe('多组件AND查询', () => {
it('应该能查询Transform+Physics组件', () => {
const result = componentIndex.queryMultiple([TransformComponent, PhysicsComponent], 'AND');
expect(result.size).toBe(2);
expect(result.has(entities[1])).toBe(true);
expect(result.has(entities[3])).toBe(true);
});
it('应该能查询Physics+Audio组件', () => {
const result = componentIndex.queryMultiple([PhysicsComponent, AudioComponent], 'AND');
expect(result.size).toBe(2);
expect(result.has(entities[2])).toBe(true);
expect(result.has(entities[3])).toBe(true);
});
it('应该能查询Transform+Physics+Audio组件', () => {
const result = componentIndex.queryMultiple([TransformComponent, PhysicsComponent, AudioComponent], 'AND');
expect(result.size).toBe(1);
expect(result.has(entities[3])).toBe(true);
});
it('应该处理不存在的组合', () => {
const result = componentIndex.queryMultiple([TransformComponent, GraphicsComponent], 'AND');
expect(result.size).toBe(0);
});
});
describe('多组件OR查询', () => {
it('应该能查询Transform或Graphics组件', () => {
const result = componentIndex.queryMultiple([TransformComponent, GraphicsComponent], 'OR');
expect(result.size).toBe(4);
expect(result.has(entities[0])).toBe(true);
expect(result.has(entities[1])).toBe(true);
expect(result.has(entities[3])).toBe(true);
expect(result.has(entities[4])).toBe(true);
});
it('应该能查询Audio或Graphics组件', () => {
const result = componentIndex.queryMultiple([AudioComponent, GraphicsComponent], 'OR');
expect(result.size).toBe(3);
expect(result.has(entities[2])).toBe(true);
expect(result.has(entities[3])).toBe(true);
expect(result.has(entities[4])).toBe(true);
});
it('应该能查询所有组件类型', () => {
const result = componentIndex.queryMultiple([
TransformComponent,
PhysicsComponent,
AudioComponent,
GraphicsComponent
], 'OR');
expect(result.size).toBe(5);
});
});
describe('边界情况', () => {
it('应该处理空组件列表', () => {
const andResult = componentIndex.queryMultiple([], 'AND');
const orResult = componentIndex.queryMultiple([], 'OR');
expect(andResult.size).toBe(0);
expect(orResult.size).toBe(0);
});
it('应该处理单组件查询', () => {
const result = componentIndex.queryMultiple([TransformComponent], 'AND');
const directResult = componentIndex.query(TransformComponent);
expect(result.size).toBe(directResult.size);
expect([...result]).toEqual([...directResult]);
});
it('应该处理重复添加实体', () => {
const initialStats = componentIndex.getStats();
componentIndex.addEntity(entities[0]);
const finalStats = componentIndex.getStats();
expect(finalStats.size).toBe(initialStats.size);
});
});
describe('性能统计', () => {
it('应该跟踪查询统计信息', () => {
// 执行一些查询
componentIndex.query(TransformComponent);
componentIndex.queryMultiple([PhysicsComponent, AudioComponent], 'AND');
componentIndex.queryMultiple([TransformComponent, GraphicsComponent], 'OR');
const stats = componentIndex.getStats();
expect(stats.queryCount).toBe(3);
expect(stats.avgQueryTime).toBeGreaterThanOrEqual(0);
expect(stats.memoryUsage).toBeGreaterThan(0);
expect(stats.lastUpdated).toBeGreaterThan(0);
});
it('应该提供准确的内存使用信息', () => {
const stats = componentIndex.getStats();
expect(stats.memoryUsage).toBeGreaterThan(0);
expect(stats.size).toBe(5);
});
});
describe('动态实体管理', () => {
it('应该处理实体组件变化', () => {
// 为实体添加新组件
entities[4].addComponent(new TransformComponent(100, 200, 300));
componentIndex.addEntity(entities[4]); // 重新添加以更新索引
const result = componentIndex.query(TransformComponent);
expect(result.has(entities[4])).toBe(true);
expect(result.size).toBe(4);
});
it('应该处理实体组件移除', () => {
// 验证初始状态
const initialResult = componentIndex.query(TransformComponent);
expect(initialResult.has(entities[1])).toBe(true);
expect(initialResult.size).toBe(3);
// 创建一个没有Transform组件的新实体模拟组件移除后的状态
const modifiedEntity = new Entity('modifiedEntity', entities[1].id);
modifiedEntity.addComponent(new PhysicsComponent(2.0, 0.2)); // 只保留Physics组件
// 从索引中移除原实体,添加修改后的实体
componentIndex.removeEntity(entities[1]);
componentIndex.addEntity(modifiedEntity);
const result = componentIndex.query(TransformComponent);
expect(result.has(entities[1])).toBe(false);
expect(result.has(modifiedEntity)).toBe(false);
expect(result.size).toBe(2);
// 验证Physics查询仍然能找到修改后的实体
const physicsResult = componentIndex.query(PhysicsComponent);
expect(physicsResult.has(modifiedEntity)).toBe(true);
});
});
describe('复杂查询场景', () => {
it('应该支持复杂的组合查询', () => {
// 查询有Transform和Physics但没有Audio的实体
const withTransformPhysics = componentIndex.queryMultiple([TransformComponent, PhysicsComponent], 'AND');
const withAudio = componentIndex.queryMultiple([AudioComponent], 'OR');
const withoutAudio = new Set([...withTransformPhysics].filter(e => !withAudio.has(e)));
expect(withoutAudio.size).toBe(1);
expect(withoutAudio.has(entities[1])).toBe(true);
});
it('应该支持性能敏感的批量查询', () => {
const startTime = performance.now();
// 执行大量查询
for (let i = 0; i < 100; i++) {
componentIndex.query(TransformComponent);
componentIndex.queryMultiple([PhysicsComponent, AudioComponent], 'AND');
componentIndex.queryMultiple([TransformComponent, GraphicsComponent], 'OR');
}
const duration = performance.now() - startTime;
// 应该在合理时间内完成
expect(duration).toBeLessThan(100);
const stats = componentIndex.getStats();
expect(stats.queryCount).toBe(300);
});
});
});