使用Lerna 和 monorepo管理项目结构

This commit is contained in:
YHH
2025-08-07 13:29:12 +08:00
parent 4479f0fab0
commit ea8523be35
135 changed files with 7058 additions and 372 deletions

View File

@@ -0,0 +1,309 @@
/**
* Matcher性能测试
*
* 注意:性能测试结果可能因平台而异,主要用于性能回归检测
*/
import { Scene } from '../../src/ECS/Scene';
import { Entity } from '../../src/ECS/Entity';
import { Component } from '../../src/ECS/Component';
import { Matcher } from '../../src/ECS/Utils/Matcher';
// 测试组件
class Position extends Component {
public x: number = 0;
public y: number = 0;
constructor(...args: unknown[]) {
super();
if (args.length >= 1) this.x = args[0] as number;
if (args.length >= 2) this.y = args[1] as number;
}
}
class Velocity extends Component {
public vx: number = 0;
public vy: number = 0;
constructor(...args: unknown[]) {
super();
if (args.length >= 1) this.vx = args[0] as number;
if (args.length >= 2) this.vy = args[1] as number;
}
}
class Health extends Component {
public hp: number = 100;
constructor(...args: unknown[]) {
super();
if (args.length >= 1) this.hp = args[0] as number;
}
}
class Weapon extends Component {
public damage: number = 10;
constructor(...args: unknown[]) {
super();
if (args.length >= 1) this.damage = args[0] as number;
}
}
describe('Matcher性能测试', () => {
let scene: Scene;
beforeEach(() => {
scene = new Scene();
scene.begin();
});
afterEach(() => {
scene.end();
});
const createTestEntities = (count: number): Entity[] => {
const entities: Entity[] = [];
for (let i = 0; i < count; i++) {
const entity = scene.createEntity(`Entity${i}`);
// 确定性的组件分配
if (i % 3 !== 0) entity.addComponent(new Position(i, i));
if (i % 2 === 0) entity.addComponent(new Velocity(i % 10, i % 10));
if (i % 4 !== 0) entity.addComponent(new Health(100 - (i % 50)));
if (i % 5 === 0) entity.addComponent(new Weapon(i % 20));
entities.push(entity);
}
return entities;
};
test('小规模性能测试 (100个实体)', () => {
const entities = createTestEntities(100);
const matcher = Matcher.create(scene.querySystem)
.all(Position, Velocity);
console.log('\n=== 小规模测试 (100个实体) ===');
// 传统逐个检查
const matcherStart = performance.now();
let matcherCount = 0;
for (const entity of entities) {
if (matcher.matches(entity)) {
matcherCount++;
}
}
const matcherTime = performance.now() - matcherStart;
// QuerySystem批量查询
const queryStart = performance.now();
const queryResult = scene.querySystem.queryAll(Position, Velocity);
const queryTime = performance.now() - queryStart;
// Matcher批量查询
const batchStart = performance.now();
const batchResult = matcher.query();
const batchTime = performance.now() - batchStart;
console.log(`传统逐个: ${matcherTime.toFixed(3)}ms (${matcherCount}个匹配)`);
console.log(`QuerySystem: ${queryTime.toFixed(3)}ms (${queryResult.count}个匹配)`);
console.log(`Matcher批量: ${batchTime.toFixed(3)}ms (${batchResult.length}个匹配)`);
console.log(`性能提升: ${(matcherTime/batchTime).toFixed(1)}x`);
// 验证结果一致性
expect(matcherCount).toBe(queryResult.count);
expect(batchResult.length).toBe(queryResult.count);
// 性能断言(宽松,避免平台差异)
expect(batchTime).toBeLessThan(matcherTime * 2);
});
test('中等规模性能测试 (1000个实体)', () => {
const entities = createTestEntities(1000);
const matcher = Matcher.create(scene.querySystem)
.all(Position, Velocity);
console.log('\n=== 中等规模测试 (1000个实体) ===');
// 传统方式
const matcherStart = performance.now();
let matcherCount = 0;
for (const entity of entities) {
if (matcher.matches(entity)) {
matcherCount++;
}
}
const matcherTime = performance.now() - matcherStart;
// QuerySystem方式
const queryStart = performance.now();
const queryResult = scene.querySystem.queryAll(Position, Velocity);
const queryTime = performance.now() - queryStart;
console.log(`传统逐个: ${matcherTime.toFixed(3)}ms (${matcherCount}个匹配)`);
console.log(`QuerySystem: ${queryTime.toFixed(3)}ms (${queryResult.count}个匹配)`);
console.log(`性能提升: ${(matcherTime/queryTime).toFixed(1)}x`);
expect(matcherCount).toBe(queryResult.count);
expect(queryTime).toBeLessThan(matcherTime);
});
test('大规模性能测试 (5000个实体)', () => {
const entities = createTestEntities(5000);
const matcher = Matcher.create(scene.querySystem)
.all(Position, Velocity);
console.log('\n=== 大规模测试 (5000个实体) ===');
// 传统方式
const matcherStart = performance.now();
let matcherCount = 0;
for (const entity of entities) {
if (matcher.matches(entity)) {
matcherCount++;
}
}
const matcherTime = performance.now() - matcherStart;
// QuerySystem方式
const queryStart = performance.now();
const queryResult = scene.querySystem.queryAll(Position, Velocity);
const queryTime = performance.now() - queryStart;
console.log(`传统逐个: ${matcherTime.toFixed(3)}ms (${matcherCount}个匹配)`);
console.log(`QuerySystem: ${queryTime.toFixed(3)}ms (${queryResult.count}个匹配)`);
console.log(`性能提升: ${(matcherTime/queryTime).toFixed(1)}x`);
expect(matcherCount).toBe(queryResult.count);
expect(queryTime).toBeLessThan(matcherTime);
});
test('重复查询缓存性能', () => {
createTestEntities(2000);
const matcher = Matcher.create(scene.querySystem)
.all(Position, Velocity);
const repeatCount = 10;
console.log('\n=== 重复查询缓存测试 (2000个实体, 10次查询) ===');
// 首次查询(建立缓存)
const firstResult = matcher.query();
// 重复查询测试
const repeatStart = performance.now();
for (let i = 0; i < repeatCount; i++) {
const result = matcher.query();
expect(result.length).toBe(firstResult.length);
}
const repeatTime = performance.now() - repeatStart;
// QuerySystem重复查询对比
const queryStart = performance.now();
for (let i = 0; i < repeatCount; i++) {
scene.querySystem.queryAll(Position, Velocity);
}
const queryTime = performance.now() - queryStart;
console.log(`Matcher重复: ${repeatTime.toFixed(3)}ms (${(repeatTime/repeatCount).toFixed(3)}ms/次)`);
console.log(`QuerySystem重复: ${queryTime.toFixed(3)}ms (${(queryTime/repeatCount).toFixed(3)}ms/次)`);
console.log(`缓存优势: ${(queryTime/repeatTime).toFixed(1)}x`);
// 宽松的性能断言(允许平台差异)
expect(repeatTime).toBeLessThan(queryTime * 5);
});
test('复杂查询性能测试', () => {
const entities = createTestEntities(1000);
console.log('\n=== 复杂查询测试 (1000个实体) ===');
console.log('查询条件: all(Position) + any(Velocity, Weapon) + none(Health)');
// Matcher复杂查询
const matcher = Matcher.create(scene.querySystem)
.all(Position)
.any(Velocity, Weapon)
.none(Health);
const matcherStart = performance.now();
let matcherCount = 0;
for (const entity of entities) {
if (matcher.matches(entity)) {
matcherCount++;
}
}
const matcherTime = performance.now() - matcherStart;
// QuerySystem分步查询
const queryStart = performance.now();
const posResult = scene.querySystem.queryAll(Position);
const velResult = scene.querySystem.queryAll(Velocity);
const weaponResult = scene.querySystem.queryAll(Weapon);
const healthResult = scene.querySystem.queryAll(Health);
const posSet = new Set(posResult.entities);
const velSet = new Set(velResult.entities);
const weaponSet = new Set(weaponResult.entities);
const healthSet = new Set(healthResult.entities);
let queryCount = 0;
for (const entity of entities) {
const hasPos = posSet.has(entity);
const hasVelOrWeapon = velSet.has(entity) || weaponSet.has(entity);
const hasHealth = healthSet.has(entity);
if (hasPos && hasVelOrWeapon && !hasHealth) {
queryCount++;
}
}
const queryTime = performance.now() - queryStart;
console.log(`Matcher复杂: ${matcherTime.toFixed(3)}ms (${matcherCount}个匹配)`);
console.log(`分步QuerySystem: ${queryTime.toFixed(3)}ms (${queryCount}个匹配)`);
console.log(`性能比: ${(matcherTime/queryTime).toFixed(2)}x`);
// 验证结果一致性
expect(matcherCount).toBe(queryCount);
// 宽松的性能断言(复杂查询可能有差异)
expect(matcherTime).toBeLessThan(queryTime * 10);
});
test('缓存失效性能影响', () => {
createTestEntities(1000);
const matcher = Matcher.create(scene.querySystem)
.all(Position);
console.log('\n=== 缓存失效性能测试 ===');
// 首次查询
const firstStart = performance.now();
const firstResult = matcher.query();
const firstTime = performance.now() - firstStart;
// 重复查询(缓存命中)
const cachedStart = performance.now();
const cachedResult = matcher.query();
const cachedTime = performance.now() - cachedStart;
// 添加新实体(使缓存失效)
const newEntity = scene.createEntity('CacheInvalidator');
newEntity.addComponent(new Position(999, 999));
// 缓存失效后的查询
const invalidatedStart = performance.now();
const invalidatedResult = matcher.query();
const invalidatedTime = performance.now() - invalidatedStart;
console.log(`首次查询: ${firstTime.toFixed(3)}ms (${firstResult.length}个结果)`);
console.log(`缓存查询: ${cachedTime.toFixed(3)}ms (${cachedResult.length}个结果)`);
console.log(`失效查询: ${invalidatedTime.toFixed(3)}ms (${invalidatedResult.length}个结果)`);
// 验证功能正确性
expect(cachedResult.length).toBe(firstResult.length);
expect(invalidatedResult.length).toBe(firstResult.length + 1);
// 性能验证
expect(cachedTime).toBeLessThan(firstTime);
expect(invalidatedTime).toBeGreaterThan(cachedTime);
});
});