优化matcher内部实现改为querysystem
完善type类型 更新文档
This commit is contained in:
@@ -1,299 +0,0 @@
|
||||
import { Scene } from '../../../src/ECS/Scene';
|
||||
import { Entity } from '../../../src/ECS/Entity';
|
||||
import { Component } from '../../../src/ECS/Component';
|
||||
import { EntitySystem } from '../../../src/ECS/Systems/EntitySystem';
|
||||
import { Matcher } from '../../../src/ECS/Utils/Matcher';
|
||||
import { ComponentTypeManager } from '../../../src/ECS/Utils/ComponentTypeManager';
|
||||
|
||||
class PositionComponent extends Component {
|
||||
constructor(public x: number = 0, public y: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class VelocityComponent extends Component {
|
||||
constructor(public vx: number = 0, public vy: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class HealthComponent extends Component {
|
||||
constructor(public health: number = 100) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class MovementSystem extends EntitySystem {
|
||||
public processedEntities: Entity[] = [];
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(PositionComponent, VelocityComponent));
|
||||
}
|
||||
|
||||
public override onChanged(entity: Entity): void {
|
||||
if (this.matcher.isInterestedEntity(entity)) {
|
||||
if (!this.processedEntities.includes(entity)) {
|
||||
this.processedEntities.push(entity);
|
||||
}
|
||||
} else {
|
||||
const index = this.processedEntities.indexOf(entity);
|
||||
if (index !== -1) {
|
||||
this.processedEntities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HealthSystem extends EntitySystem {
|
||||
public processedEntities: Entity[] = [];
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(HealthComponent).exclude(VelocityComponent));
|
||||
}
|
||||
|
||||
public override onChanged(entity: Entity): void {
|
||||
if (this.matcher.isInterestedEntity(entity)) {
|
||||
if (!this.processedEntities.includes(entity)) {
|
||||
this.processedEntities.push(entity);
|
||||
}
|
||||
} else {
|
||||
const index = this.processedEntities.indexOf(entity);
|
||||
if (index !== -1) {
|
||||
this.processedEntities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CombatSystem extends EntitySystem {
|
||||
public processedEntities: Entity[] = [];
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty()
|
||||
.all(PositionComponent)
|
||||
.one(VelocityComponent, HealthComponent));
|
||||
}
|
||||
|
||||
public override onChanged(entity: Entity): void {
|
||||
if (this.matcher.isInterestedEntity(entity)) {
|
||||
if (!this.processedEntities.includes(entity)) {
|
||||
this.processedEntities.push(entity);
|
||||
}
|
||||
} else {
|
||||
const index = this.processedEntities.indexOf(entity);
|
||||
if (index !== -1) {
|
||||
this.processedEntities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('Matcher时序集成测试', () => {
|
||||
let scene: Scene;
|
||||
let movementSystem: MovementSystem;
|
||||
let healthSystem: HealthSystem;
|
||||
let combatSystem: CombatSystem;
|
||||
|
||||
beforeEach(() => {
|
||||
ComponentTypeManager.instance.reset();
|
||||
scene = new Scene();
|
||||
movementSystem = new MovementSystem();
|
||||
healthSystem = new HealthSystem();
|
||||
combatSystem = new CombatSystem();
|
||||
});
|
||||
|
||||
describe('先添加实体,再添加系统', () => {
|
||||
test('MovementSystem应该正确过滤实体', () => {
|
||||
// 创建各种类型的实体
|
||||
const movingEntity = scene.createEntity('MovingEntity');
|
||||
movingEntity.addComponent(new PositionComponent(10, 20));
|
||||
movingEntity.addComponent(new VelocityComponent(1, 1));
|
||||
|
||||
const staticEntity = scene.createEntity('StaticEntity');
|
||||
staticEntity.addComponent(new PositionComponent(30, 40));
|
||||
|
||||
const healthEntity = scene.createEntity('HealthEntity');
|
||||
healthEntity.addComponent(new HealthComponent(80));
|
||||
|
||||
const complexEntity = scene.createEntity('ComplexEntity');
|
||||
complexEntity.addComponent(new PositionComponent(50, 60));
|
||||
complexEntity.addComponent(new VelocityComponent(2, 2));
|
||||
complexEntity.addComponent(new HealthComponent(120));
|
||||
|
||||
// 添加系统 - 应该发现已存在的匹配实体
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
|
||||
// MovementSystem需要Position + Velocity
|
||||
expect(movementSystem.processedEntities).toHaveLength(2);
|
||||
expect(movementSystem.processedEntities).toContain(movingEntity);
|
||||
expect(movementSystem.processedEntities).toContain(complexEntity);
|
||||
expect(movementSystem.processedEntities).not.toContain(staticEntity);
|
||||
expect(movementSystem.processedEntities).not.toContain(healthEntity);
|
||||
});
|
||||
|
||||
test('HealthSystem应该正确过滤实体', () => {
|
||||
// 创建实体
|
||||
const healthOnlyEntity = scene.createEntity('HealthOnly');
|
||||
healthOnlyEntity.addComponent(new HealthComponent(100));
|
||||
|
||||
const movingHealthEntity = scene.createEntity('MovingHealth');
|
||||
movingHealthEntity.addComponent(new HealthComponent(80));
|
||||
movingHealthEntity.addComponent(new VelocityComponent(1, 1));
|
||||
|
||||
const positionHealthEntity = scene.createEntity('PositionHealth');
|
||||
positionHealthEntity.addComponent(new PositionComponent(10, 20));
|
||||
positionHealthEntity.addComponent(new HealthComponent(90));
|
||||
|
||||
// 添加系统
|
||||
scene.addEntityProcessor(healthSystem);
|
||||
|
||||
// HealthSystem需要Health但不要Velocity
|
||||
expect(healthSystem.processedEntities).toHaveLength(2);
|
||||
expect(healthSystem.processedEntities).toContain(healthOnlyEntity);
|
||||
expect(healthSystem.processedEntities).toContain(positionHealthEntity);
|
||||
expect(healthSystem.processedEntities).not.toContain(movingHealthEntity); // 被exclude排除
|
||||
});
|
||||
|
||||
test('CombatSystem复杂匹配应该正确工作', () => {
|
||||
// 创建实体
|
||||
const warriorEntity = scene.createEntity('Warrior');
|
||||
warriorEntity.addComponent(new PositionComponent(10, 20));
|
||||
warriorEntity.addComponent(new VelocityComponent(1, 1));
|
||||
|
||||
const guardEntity = scene.createEntity('Guard');
|
||||
guardEntity.addComponent(new PositionComponent(30, 40));
|
||||
guardEntity.addComponent(new HealthComponent(100));
|
||||
|
||||
const archerEntity = scene.createEntity('Archer');
|
||||
archerEntity.addComponent(new PositionComponent(50, 60));
|
||||
archerEntity.addComponent(new VelocityComponent(2, 2));
|
||||
archerEntity.addComponent(new HealthComponent(80));
|
||||
|
||||
const structureEntity = scene.createEntity('Structure');
|
||||
structureEntity.addComponent(new PositionComponent(70, 80));
|
||||
|
||||
// 添加系统
|
||||
scene.addEntityProcessor(combatSystem);
|
||||
|
||||
// CombatSystem需要Position + (Velocity OR Health)
|
||||
expect(combatSystem.processedEntities).toHaveLength(3);
|
||||
expect(combatSystem.processedEntities).toContain(warriorEntity); // Position + Velocity
|
||||
expect(combatSystem.processedEntities).toContain(guardEntity); // Position + Health
|
||||
expect(combatSystem.processedEntities).toContain(archerEntity); // Position + Both
|
||||
expect(combatSystem.processedEntities).not.toContain(structureEntity); // 只有Position
|
||||
});
|
||||
});
|
||||
|
||||
describe('先添加系统,再添加实体', () => {
|
||||
test('系统应该动态发现新添加的实体', () => {
|
||||
// 先添加系统
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
scene.addEntityProcessor(healthSystem);
|
||||
scene.addEntityProcessor(combatSystem);
|
||||
|
||||
expect(movementSystem.processedEntities).toHaveLength(0);
|
||||
expect(healthSystem.processedEntities).toHaveLength(0);
|
||||
expect(combatSystem.processedEntities).toHaveLength(0);
|
||||
|
||||
// 添加匹配MovementSystem的实体
|
||||
const movingEntity = scene.createEntity('MovingEntity');
|
||||
movingEntity.addComponent(new PositionComponent(10, 20));
|
||||
movingEntity.addComponent(new VelocityComponent(1, 1));
|
||||
|
||||
expect(movementSystem.processedEntities).toHaveLength(1);
|
||||
expect(movementSystem.processedEntities).toContain(movingEntity);
|
||||
expect(combatSystem.processedEntities).toContain(movingEntity); // 也匹配CombatSystem
|
||||
|
||||
// 添加只匹配HealthSystem的实体
|
||||
const healthEntity = scene.createEntity('HealthEntity');
|
||||
healthEntity.addComponent(new HealthComponent(100));
|
||||
|
||||
expect(healthSystem.processedEntities).toHaveLength(1);
|
||||
expect(healthSystem.processedEntities).toContain(healthEntity);
|
||||
expect(movementSystem.processedEntities).toHaveLength(1); // 不变
|
||||
|
||||
// 添加匹配CombatSystem但不匹配其他的实体
|
||||
const guardEntity = scene.createEntity('GuardEntity');
|
||||
guardEntity.addComponent(new PositionComponent(30, 40));
|
||||
guardEntity.addComponent(new HealthComponent(120));
|
||||
|
||||
expect(combatSystem.processedEntities).toHaveLength(2);
|
||||
expect(combatSystem.processedEntities).toContain(guardEntity);
|
||||
expect(movementSystem.processedEntities).toHaveLength(1); // 不变
|
||||
expect(healthSystem.processedEntities).toHaveLength(2); // 增加
|
||||
});
|
||||
});
|
||||
|
||||
describe('混合时序和动态组件变化', () => {
|
||||
test('实体组件的动态添加移除应该正确更新所有系统', () => {
|
||||
// 先添加一些系统
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
|
||||
// 创建一个只有位置的实体
|
||||
const entity = scene.createEntity('DynamicEntity');
|
||||
entity.addComponent(new PositionComponent(10, 20));
|
||||
|
||||
expect(movementSystem.processedEntities).toHaveLength(0); // 缺少Velocity
|
||||
|
||||
// 后添加健康系统
|
||||
scene.addEntityProcessor(healthSystem);
|
||||
expect(healthSystem.processedEntities).toHaveLength(0); // 实体没有Health
|
||||
|
||||
// 添加速度组件 - 应该被MovementSystem发现
|
||||
entity.addComponent(new VelocityComponent(1, 1));
|
||||
expect(movementSystem.processedEntities).toHaveLength(1);
|
||||
expect(movementSystem.processedEntities).toContain(entity);
|
||||
|
||||
// 添加战斗系统
|
||||
scene.addEntityProcessor(combatSystem);
|
||||
expect(combatSystem.processedEntities).toContain(entity); // Position + Velocity
|
||||
|
||||
// 添加健康组件
|
||||
entity.addComponent(new HealthComponent(100));
|
||||
expect(healthSystem.processedEntities).toHaveLength(0); // 被Velocity排除
|
||||
expect(combatSystem.processedEntities).toContain(entity); // 仍然匹配
|
||||
|
||||
// 移除速度组件
|
||||
const velocityComponent = entity.getComponent(VelocityComponent);
|
||||
if (velocityComponent) {
|
||||
entity.removeComponent(velocityComponent);
|
||||
}
|
||||
|
||||
expect(movementSystem.processedEntities).toHaveLength(0); // 不再匹配
|
||||
expect(healthSystem.processedEntities).toContain(entity); // 现在匹配了
|
||||
expect(combatSystem.processedEntities).toContain(entity); // Position + Health
|
||||
});
|
||||
});
|
||||
|
||||
describe('场景生命周期测试', () => {
|
||||
test('场景begin()后系统过滤仍然正常工作', () => {
|
||||
// 添加实体和系统
|
||||
const entity1 = scene.createEntity('Entity1');
|
||||
entity1.addComponent(new PositionComponent(10, 20));
|
||||
entity1.addComponent(new VelocityComponent(1, 1));
|
||||
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
|
||||
expect(movementSystem.processedEntities).toContain(entity1);
|
||||
|
||||
// 调用场景begin
|
||||
scene.begin();
|
||||
|
||||
// 添加新实体应该仍然正常工作
|
||||
const entity2 = scene.createEntity('Entity2');
|
||||
entity2.addComponent(new PositionComponent(30, 40));
|
||||
entity2.addComponent(new VelocityComponent(2, 2));
|
||||
|
||||
expect(movementSystem.processedEntities).toHaveLength(2);
|
||||
expect(movementSystem.processedEntities).toContain(entity2);
|
||||
|
||||
// 动态添加系统也应该正常工作
|
||||
scene.addEntityProcessor(healthSystem);
|
||||
|
||||
const healthEntity = scene.createEntity('HealthEntity');
|
||||
healthEntity.addComponent(new HealthComponent(100));
|
||||
|
||||
expect(healthSystem.processedEntities).toContain(healthEntity);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user