646 lines
20 KiB
Markdown
646 lines
20 KiB
Markdown
# QuerySystem 使用指南
|
||
|
||
QuerySystem 是 ECS Framework 中的高性能实体查询系统,支持多级索引、智能缓存和类型安全的查询操作。
|
||
|
||
## 基本用法
|
||
|
||
### 1. 获取查询系统
|
||
|
||
```typescript
|
||
import { Scene, Entity } from '@esengine/ecs-framework';
|
||
|
||
// 创建场景,查询系统会自动创建
|
||
const scene = new Scene();
|
||
const querySystem = scene.querySystem;
|
||
|
||
// 或者从Core获取当前场景的查询系统
|
||
import { Core } from '@esengine/ecs-framework';
|
||
const currentQuerySystem = Core.scene?.querySystem;
|
||
```
|
||
|
||
### 2. 基本查询操作
|
||
|
||
```typescript
|
||
// 查询包含所有指定组件的实体
|
||
const result = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||
console.log(`找到 ${result.count} 个实体`);
|
||
|
||
// 查询包含任意指定组件的实体
|
||
const anyResult = querySystem.queryAny(HealthComponent, ManaComponent);
|
||
|
||
// 查询不包含指定组件的实体
|
||
const noneResult = querySystem.queryNone(DeadComponent);
|
||
```
|
||
|
||
### 3. 类型安全查询
|
||
|
||
```typescript
|
||
// 类型安全的查询,返回实体和对应的组件
|
||
const typedResult = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||
for (let i = 0; i < typedResult.entities.length; i++) {
|
||
const entity = typedResult.entities[i];
|
||
const [position, velocity] = typedResult.components[i];
|
||
// position 和 velocity 都是类型安全的
|
||
}
|
||
|
||
// 查询单个组件类型
|
||
const healthResult = querySystem.queryAll(HealthComponent);
|
||
for (const entity of healthResult.entities) {
|
||
const health = entity.getComponent(HealthComponent);
|
||
if (health) {
|
||
console.log(`实体 ${entity.name} 的生命值: ${health.value}`);
|
||
}
|
||
}
|
||
|
||
// 查询两个组件类型
|
||
const movableResult = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||
for (const entity of movableResult.entities) {
|
||
const position = entity.getComponent(PositionComponent);
|
||
const velocity = entity.getComponent(VelocityComponent);
|
||
if (position && velocity) {
|
||
// 更新位置
|
||
position.x += velocity.x;
|
||
position.y += velocity.y;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 使用查询构建器
|
||
|
||
```typescript
|
||
// QuerySystem不提供查询构建器,请使用Matcher进行复杂查询
|
||
// 推荐使用Matcher配合EntitySystem
|
||
|
||
import { Matcher } from '@esengine/ecs-framework';
|
||
|
||
// 创建复杂查询条件
|
||
const visibleMatcher = Matcher.all(PositionComponent, RenderComponent)
|
||
.none(HiddenComponent);
|
||
|
||
// 通过QuerySystem执行查询
|
||
const visibleEntities = querySystem.query(visibleMatcher.getCondition());
|
||
|
||
// 过滤和排序需要手动处理
|
||
const sortedEntities = visibleEntities.entities
|
||
.filter(entity => entity.name.startsWith('Boss'))
|
||
.sort((a, b) => a.id - b.id)
|
||
.slice(0, 10); // 限制数量
|
||
|
||
// 迭代结果
|
||
sortedEntities.forEach((entity, index) => {
|
||
console.log(`敌人 ${index}: ${entity.name}`);
|
||
});
|
||
```
|
||
|
||
### 5. 高级查询功能
|
||
|
||
```typescript
|
||
// QuerySystem主要提供基础查询方法
|
||
// 复杂查询推荐使用Matcher和EntitySystem
|
||
|
||
// 基本查询
|
||
const positionResult = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||
const healthResult = querySystem.queryAll(HealthComponent);
|
||
const manaResult = querySystem.queryAll(ManaComponent);
|
||
|
||
// 排除死亡实体的移动实体
|
||
const aliveMovingEntities = positionResult.entities.filter(entity =>
|
||
!entity.hasComponent(DeadComponent)
|
||
);
|
||
|
||
// 如果需要复杂查询,推荐在EntitySystem中使用Matcher
|
||
class ComplexQuerySystem extends EntitySystem {
|
||
constructor() {
|
||
super(Matcher.all(PositionComponent, VelocityComponent).none(DeadComponent));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是过滤后的结果
|
||
for (const entity of entities) {
|
||
// 处理逻辑
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 场景级别的实体查询
|
||
|
||
除了使用QuerySystem,您还可以直接使用Scene提供的便捷查询方法:
|
||
|
||
### 基本场景查询
|
||
|
||
```typescript
|
||
// 按名称查找实体
|
||
const player = scene.findEntity("Player");
|
||
const playerAlt = scene.getEntityByName("Player"); // 别名方法
|
||
|
||
// 按ID查找实体
|
||
const entity = scene.findEntityById(123);
|
||
|
||
// 按标签查找实体
|
||
const enemies = scene.findEntitiesByTag(2);
|
||
const enemiesAlt = scene.getEntitiesByTag(2); // 别名方法
|
||
|
||
// 获取所有实体
|
||
const allEntities = scene.entities.buffer;
|
||
```
|
||
|
||
## 性能优化
|
||
|
||
### 1. 缓存管理
|
||
|
||
```typescript
|
||
// 设置缓存配置
|
||
querySystem.setCacheConfig(200, 2000); // 最大200个缓存项,2秒超时
|
||
|
||
// 清空缓存
|
||
querySystem.clearCache();
|
||
|
||
// 预热常用查询(使用基础查询方法)
|
||
querySystem.queryAll(PositionComponent); // 预热Position查询
|
||
querySystem.queryAll(VelocityComponent); // 预热Velocity查询
|
||
```
|
||
|
||
### 2. 索引优化
|
||
|
||
```typescript
|
||
// 获取性能统计
|
||
const stats = querySystem.getStats();
|
||
console.log(`缓存命中率: ${(stats.hitRate * 100).toFixed(1)}%`);
|
||
console.log(`实体数量: ${stats.entityCount}`);
|
||
|
||
// 获取详细性能报告
|
||
const report = querySystem.getPerformanceReport();
|
||
console.log(report);
|
||
```
|
||
|
||
### 3. 查询监听和快照
|
||
|
||
```typescript
|
||
// QuerySystem主要用于基础查询,高级功能请使用EntitySystem和事件系统
|
||
|
||
// 如需监听实体变化,使用事件系统
|
||
scene.entityManager.eventBus.on('entity:added', (entity) => {
|
||
if (entity.hasComponent(EnemyComponent)) {
|
||
console.log('新增敌人实体');
|
||
}
|
||
});
|
||
|
||
scene.entityManager.eventBus.on('entity:removed', (entity) => {
|
||
if (entity.hasComponent(EnemyComponent)) {
|
||
console.log('移除敌人实体');
|
||
}
|
||
});
|
||
|
||
// 手动创建快照进行比较
|
||
const snapshot1 = querySystem.queryAll(PlayerComponent).entities.map(e => e.id);
|
||
// 稍后
|
||
const snapshot2 = querySystem.queryAll(PlayerComponent).entities.map(e => e.id);
|
||
|
||
// 比较快照
|
||
const added = snapshot2.filter(id => !snapshot1.includes(id));
|
||
const removed = snapshot1.filter(id => !snapshot2.includes(id));
|
||
console.log(`新增: ${added.length}, 移除: ${removed.length}`);
|
||
```
|
||
|
||
## 使用Matcher进行高级查询
|
||
|
||
Matcher是一个优雅的查询封装器,提供流畅的API和强大的缓存机制。
|
||
|
||
### 基本Matcher用法
|
||
|
||
```typescript
|
||
import { Matcher } from '@esengine/ecs-framework';
|
||
|
||
// 创建Matcher查询条件
|
||
const movingMatcher = Matcher.all(PositionComponent, VelocityComponent);
|
||
// 在QuerySystem中需要使用基础查询方法
|
||
const movingEntities = scene.querySystem.queryAll(PositionComponent, VelocityComponent).entities;
|
||
|
||
// 复合查询需要使用EntitySystem或手动过滤
|
||
const aliveEnemiesMatcher = Matcher.all(EnemyComponent, HealthComponent)
|
||
.any(WeaponComponent, MagicComponent)
|
||
.none(DeadComponent, StunnedComponent);
|
||
|
||
// 在EntitySystem中使用
|
||
class AliveEnemySystem extends EntitySystem {
|
||
constructor() {
|
||
super(aliveEnemiesMatcher);
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是匹配的实体
|
||
for (const entity of entities) {
|
||
// 处理存活的敌人
|
||
}
|
||
}
|
||
}
|
||
|
||
// 或者手动过滤
|
||
const enemyResult = scene.querySystem.queryAll(EnemyComponent, HealthComponent);
|
||
const aliveEnemies = enemyResult.entities.filter(entity => {
|
||
const hasWeaponOrMagic = entity.hasComponent(WeaponComponent) || entity.hasComponent(MagicComponent);
|
||
const isAlive = !entity.hasComponent(DeadComponent) && !entity.hasComponent(StunnedComponent);
|
||
return hasWeaponOrMagic && isAlive;
|
||
});
|
||
|
||
// 单个实体检查
|
||
const playerResult = scene.querySystem.queryAll(PlayerComponent);
|
||
if (playerResult.entities.includes(someEntity)) {
|
||
console.log('这是玩家实体');
|
||
}
|
||
|
||
// 统计信息
|
||
console.log(`玩家数量: ${playerResult.count}`);
|
||
console.log(`是否有玩家: ${playerResult.count > 0}`);
|
||
```
|
||
|
||
### 系统中使用Matcher
|
||
|
||
```typescript
|
||
import { EntitySystem, Entity, Matcher } from '@esengine/ecs-framework';
|
||
|
||
class MovementSystem extends EntitySystem {
|
||
constructor() {
|
||
// 在构造函数中直接传入Matcher
|
||
super(Matcher.all(PositionComponent, VelocityComponent));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities参数已经是系统自动过滤后的实体
|
||
for (const entity of entities) {
|
||
const position = entity.getComponent(PositionComponent)!;
|
||
const velocity = entity.getComponent(VelocityComponent)!;
|
||
|
||
// 更新位置
|
||
position.x += velocity.x * Time.deltaTime;
|
||
position.y += velocity.y * Time.deltaTime;
|
||
|
||
// 边界检查
|
||
if (position.x < 0 || position.x > 800) {
|
||
velocity.x = -velocity.x;
|
||
}
|
||
if (position.y < 0 || position.y > 600) {
|
||
velocity.y = -velocity.y;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 碰撞检测示例
|
||
|
||
```typescript
|
||
class CollisionSystem extends EntitySystem {
|
||
constructor() {
|
||
// 在构造函数中传入Matcher
|
||
super(Matcher.all(PositionComponent, ColliderComponent));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是匹配的实体
|
||
const collidableEntities = entities;
|
||
|
||
// 检测碰撞
|
||
for (let i = 0; i < collidableEntities.length; i++) {
|
||
for (let j = i + 1; j < collidableEntities.length; j++) {
|
||
const entityA = collidableEntities[i];
|
||
const entityB = collidableEntities[j];
|
||
|
||
if (this.checkCollision(entityA, entityB)) {
|
||
this.handleCollision(entityA, entityB);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private checkCollision(entityA: Entity, entityB: Entity): boolean {
|
||
const posA = entityA.getComponent(PositionComponent)!;
|
||
const posB = entityB.getComponent(PositionComponent)!;
|
||
const distance = Math.sqrt(
|
||
Math.pow(posA.x - posB.x, 2) + Math.pow(posA.y - posB.y, 2)
|
||
);
|
||
return distance < 50;
|
||
}
|
||
|
||
private handleCollision(entityA: Entity, entityB: Entity): void {
|
||
console.log(`碰撞检测: ${entityA.name} 与 ${entityB.name}`);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 生命值管理示例
|
||
|
||
```typescript
|
||
class HealthSystem extends EntitySystem {
|
||
constructor() {
|
||
// 在构造函数中传入Matcher
|
||
super(Matcher.all(HealthComponent));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是匹配的实体
|
||
const healthEntities = entities;
|
||
const deadEntities: Entity[] = [];
|
||
|
||
for (const entity of healthEntities) {
|
||
const health = entity.getComponent(HealthComponent)!;
|
||
|
||
// 检查死亡
|
||
if (health.currentHealth <= 0) {
|
||
deadEntities.push(entity);
|
||
}
|
||
}
|
||
|
||
// 移除死亡实体
|
||
deadEntities.forEach(entity => {
|
||
console.log(`实体 ${entity.name} 已死亡`);
|
||
entity.destroy();
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
### Matcher完整API参考
|
||
|
||
#### 静态创建方法
|
||
|
||
```typescript
|
||
// 基础静态方法
|
||
const allMatcher = Matcher.all(PositionComponent, VelocityComponent); // 必须包含所有组件
|
||
const anyMatcher = Matcher.any(WeaponComponent, MagicComponent); // 必须包含任意一个组件
|
||
const noneMatcher = Matcher.none(DeadComponent, DisabledComponent); // 不能包含任何指定组件
|
||
|
||
// 特殊查询静态方法
|
||
const tagMatcher = Matcher.byTag(1); // 按标签查询
|
||
const nameMatcher = Matcher.byName("Player"); // 按名称查询
|
||
const componentMatcher = Matcher.byComponent(HealthComponent); // 单组件查询
|
||
|
||
// 构建器方法
|
||
const complexMatcher = Matcher.complex(); // 创建复杂查询构建器
|
||
const emptyMatcher = Matcher.empty(); // 创建空匹配器
|
||
```
|
||
|
||
#### 实例方法 - 条件构建
|
||
|
||
```typescript
|
||
// 基础条件方法
|
||
const matcher = Matcher.empty()
|
||
.all(PositionComponent, VelocityComponent) // 必须包含所有组件
|
||
.any(WeaponComponent, MagicComponent) // 必须包含任意一个组件
|
||
.none(DeadComponent, StunnedComponent); // 不能包含任何指定组件
|
||
|
||
// 别名方法(提供更语义化的API)
|
||
const semanticMatcher = Matcher.empty()
|
||
.all(PositionComponent)
|
||
.exclude(DeadComponent) // exclude() 等同于 none()
|
||
.one(WeaponComponent, MagicComponent); // one() 等同于 any()
|
||
|
||
// 特殊条件方法
|
||
const advancedMatcher = Matcher.empty()
|
||
.all(EnemyComponent)
|
||
.withTag(2) // 指定标签
|
||
.withName("Boss") // 指定名称
|
||
.withComponent(HealthComponent); // 单组件条件
|
||
```
|
||
|
||
#### 条件移除方法
|
||
|
||
```typescript
|
||
// 移除特殊条件
|
||
const matcher = Matcher.byTag(1)
|
||
.withName("Player")
|
||
.withComponent(HealthComponent);
|
||
|
||
// 移除各种条件
|
||
matcher.withoutTag(); // 移除标签条件
|
||
matcher.withoutName(); // 移除名称条件
|
||
matcher.withoutComponent(); // 移除单组件条件
|
||
```
|
||
|
||
#### 实用工具方法
|
||
|
||
```typescript
|
||
// 检查和调试
|
||
const matcher = Matcher.all(PositionComponent, VelocityComponent)
|
||
.none(DeadComponent);
|
||
|
||
// 检查是否为空条件
|
||
if (matcher.isEmpty()) {
|
||
console.log('匹配器没有设置任何条件');
|
||
}
|
||
|
||
// 获取条件信息(只读)
|
||
const condition = matcher.getCondition();
|
||
console.log('必须组件:', condition.all.map(c => c.name));
|
||
console.log('任选组件:', condition.any.map(c => c.name));
|
||
console.log('排除组件:', condition.none.map(c => c.name));
|
||
console.log('标签:', condition.tag);
|
||
console.log('名称:', condition.name);
|
||
console.log('单组件:', condition.component?.name);
|
||
|
||
// 调试输出
|
||
console.log('匹配器描述:', matcher.toString());
|
||
// 输出: "Matcher[all(PositionComponent, VelocityComponent) & none(DeadComponent)]"
|
||
```
|
||
|
||
#### 克隆和重置
|
||
|
||
```typescript
|
||
// 克隆匹配器
|
||
const baseMatcher = Matcher.all(PositionComponent);
|
||
const livingMatcher = baseMatcher.clone().all(HealthComponent).none(DeadComponent);
|
||
const deadMatcher = baseMatcher.clone().all(DeadComponent);
|
||
|
||
// 重置匹配器
|
||
const reusableMatcher = Matcher.all(PositionComponent);
|
||
console.log(reusableMatcher.toString()); // "Matcher[all(PositionComponent)]"
|
||
|
||
reusableMatcher.reset(); // 清空所有条件
|
||
console.log(reusableMatcher.toString()); // "Matcher[]"
|
||
|
||
reusableMatcher.all(PlayerComponent); // 重新设置条件
|
||
console.log(reusableMatcher.toString()); // "Matcher[all(PlayerComponent)]"
|
||
```
|
||
|
||
#### 链式调用示例
|
||
|
||
```typescript
|
||
// 复杂的链式调用
|
||
const complexMatcher = Matcher.empty()
|
||
.all(PositionComponent, RenderComponent) // 必须有位置和渲染组件
|
||
.any(PlayerComponent, NPCComponent) // 必须是玩家或NPC
|
||
.none(DeadComponent, HiddenComponent) // 不能死亡或隐藏
|
||
.withTag(1) // 标签为1
|
||
.exclude(DisabledComponent); // 不能被禁用
|
||
|
||
// 在EntitySystem中使用
|
||
class VisibleCharacterSystem extends EntitySystem {
|
||
constructor() {
|
||
super(complexMatcher);
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是符合所有条件的实体
|
||
for (const entity of entities) {
|
||
// 处理可见角色的逻辑
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 1. Matcher使用建议
|
||
|
||
```typescript
|
||
// 推荐的用法:
|
||
const matcher = Matcher.all(Position, Velocity);
|
||
|
||
// 在系统中使用
|
||
class MySystem extends EntitySystem {
|
||
constructor() {
|
||
super(Matcher.all(RequiredComponent));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是系统自动过滤的结果
|
||
for (const entity of entities) {
|
||
// 处理逻辑...
|
||
}
|
||
}
|
||
}
|
||
|
||
// 避免在process方法中重复查询
|
||
class InefficientSystem extends EntitySystem {
|
||
protected process(entities: Entity[]): void {
|
||
// 不必要的额外查询,性能差
|
||
const condition = Matcher.all(RequiredComponent).getCondition();
|
||
const result = this.scene.querySystem.query(condition);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Matcher API最佳实践
|
||
|
||
#### 选择合适的创建方式
|
||
|
||
```typescript
|
||
// 推荐:单一条件使用静态方法
|
||
const movingEntities = Matcher.all(PositionComponent, VelocityComponent);
|
||
const playerEntities = Matcher.byTag(PLAYER_TAG);
|
||
const specificEntity = Matcher.byName("Boss");
|
||
|
||
// 推荐:复杂条件使用链式调用
|
||
const complexMatcher = Matcher.empty()
|
||
.all(PositionComponent, HealthComponent)
|
||
.any(WeaponComponent, MagicComponent)
|
||
.none(DeadComponent);
|
||
|
||
// ❌ 不推荐:简单条件使用复杂语法
|
||
const simpleButBad = Matcher.empty().all(PositionComponent);
|
||
// 应该用: Matcher.all(PositionComponent)
|
||
```
|
||
|
||
#### 合理使用别名方法
|
||
|
||
```typescript
|
||
// 使用语义化的别名提高可读性
|
||
const combatUnits = Matcher.all(PositionComponent, HealthComponent)
|
||
.one(WeaponComponent, MagicComponent) // one() 比 any() 更语义化
|
||
.exclude(DeadComponent, PacifistComponent); // exclude() 比 none() 更直观
|
||
```
|
||
|
||
#### 合理的克隆和重用
|
||
|
||
```typescript
|
||
// 推荐:基础匹配器重用
|
||
const livingEntityMatcher = Matcher.all(HealthComponent).none(DeadComponent);
|
||
const livingPlayerMatcher = livingEntityMatcher.clone().all(PlayerComponent);
|
||
const livingEnemyMatcher = livingEntityMatcher.clone().all(EnemyComponent);
|
||
|
||
// 推荐:重置匹配器重用
|
||
const reusableMatcher = Matcher.empty();
|
||
|
||
// 用于玩家系统
|
||
reusableMatcher.reset().all(PlayerComponent);
|
||
const playerSystem = new PlayerSystem(reusableMatcher.clone());
|
||
|
||
// 用于敌人系统
|
||
reusableMatcher.reset().all(EnemyComponent);
|
||
const enemySystem = new EnemySystem(reusableMatcher.clone());
|
||
```
|
||
|
||
#### 调试和维护
|
||
|
||
```typescript
|
||
// 在开发阶段添加调试信息
|
||
const debugMatcher = Matcher.all(ComplexComponent)
|
||
.any(VariantA, VariantB)
|
||
.none(DisabledComponent);
|
||
|
||
if (DEBUG_MODE) {
|
||
console.log('系统匹配条件:', debugMatcher.toString());
|
||
const condition = debugMatcher.getCondition();
|
||
console.log('预期匹配实体数:',
|
||
scene.querySystem.queryAll(...condition.all).count);
|
||
}
|
||
```
|
||
|
||
### 3. 查询优化
|
||
|
||
- **使用Matcher封装复杂查询**:提供更好的可读性和缓存
|
||
- **避免频繁创建查询**:在系统初始化时创建,重复使用
|
||
- **合理使用any()和none()条件**:减少不必要的实体遍历
|
||
- **利用Matcher的缓存机制**:自动优化重复查询性能
|
||
- **使用克隆方法复用基础条件**:避免重复定义相似的匹配条件
|
||
- **选择合适的静态方法**:单一条件优先使用对应的静态方法
|
||
|
||
### 3. 性能监控
|
||
|
||
- 定期检查查询性能报告
|
||
- 监控缓存命中率
|
||
- 优化频繁使用的查询
|
||
- 使用性能测试验证优化效果
|
||
|
||
### 4. 内存管理
|
||
|
||
- 及时清理不需要的查询监听器
|
||
- 合理设置缓存大小
|
||
- 避免创建过多的查询快照
|
||
- 适当使用Matcher的clone()和reset()方法
|
||
|
||
### 5. 代码组织
|
||
|
||
- **系统级别的Matcher**:在系统中创建和管理Matcher
|
||
- **查询逻辑封装**:将复杂查询封装到专门的方法中
|
||
- **条件复用**:使用clone()方法复用基础查询条件
|
||
- **清晰的命名**:给Matcher变量使用描述性的名称
|
||
|
||
### 6. 迁移指南
|
||
|
||
系统中Matcher的推荐用法:
|
||
|
||
```typescript
|
||
// 在EntitySystem中使用Matcher
|
||
class MySystem extends EntitySystem {
|
||
constructor() {
|
||
super(Matcher.all(ComponentA, ComponentB).none(ComponentC));
|
||
}
|
||
|
||
protected process(entities: Entity[]): void {
|
||
// entities已经是系统自动过滤的结果
|
||
for (const entity of entities) {
|
||
// 处理逻辑
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 使用最佳实践
|
||
|
||
- 在EntitySystem构造函数中传入Matcher
|
||
- 使用`none()`来排除组件
|
||
- 使用`any()`来匹配任意组件
|
||
- 直接使用EntitySystem的entities参数,避免额外查询
|
||
- 定期检查查询性能和缓存命中率 |