Files
esengine/packages/core/src/ECS/Utils/Matcher.ts

296 lines
7.4 KiB
TypeScript
Raw Normal View History

import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
/**
*
*/
interface QueryCondition {
all: ComponentType[];
any: ComponentType[];
none: ComponentType[];
tag?: number; // 按标签查询
name?: string; // 按名称查询
component?: ComponentType; // 单组件查询
}
/**
*
*
*
*
* @example
* ```typescript
* const matcher = Matcher.all(Position, Velocity)
* .any(Health, Shield)
* .none(Dead);
*
* // 获取查询条件
* const condition = matcher.getCondition();
* ```
*/
export class Matcher {
private readonly condition: QueryCondition = {
all: [],
any: [],
none: []
};
private constructor() {
// 私有构造函数,只能通过静态方法创建
}
/**
*
* @param types
*/
public static all(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.all(...types);
}
/**
*
* @param types
*/
public static any(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.any(...types);
}
/**
*
* @param types
*/
public static none(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.none(...types);
}
/**
*
* @param tag
*/
public static byTag(tag: number): Matcher {
const matcher = new Matcher();
return matcher.withTag(tag);
}
/**
*
* @param name
*/
public static byName(name: string): Matcher {
const matcher = new Matcher();
return matcher.withName(name);
}
/**
*
* @param componentType
*/
public static byComponent(componentType: ComponentType): Matcher {
const matcher = new Matcher();
return matcher.withComponent(componentType);
}
/**
*
*/
public static complex(): Matcher {
return new Matcher();
}
/**
2025-09-28 10:36:01 +08:00
*
*/
public static empty(): Matcher {
return new Matcher();
}
/**
*
* @param types
*/
public all(...types: ComponentType[]): Matcher {
this.condition.all.push(...types);
return this;
}
/**
*
* @param types
*/
public any(...types: ComponentType[]): Matcher {
this.condition.any.push(...types);
return this;
}
/**
*
* @param types
*/
public none(...types: ComponentType[]): Matcher {
this.condition.none.push(...types);
return this;
}
/**
*
* @param types
*/
public exclude(...types: ComponentType[]): Matcher {
return this.none(...types);
}
/**
*
* @param types
*/
public one(...types: ComponentType[]): Matcher {
return this.any(...types);
}
/**
*
* @param tag
*/
public withTag(tag: number): Matcher {
this.condition.tag = tag;
return this;
}
/**
*
* @param name
*/
public withName(name: string): Matcher {
this.condition.name = name;
return this;
}
/**
*
* @param componentType
*/
public withComponent(componentType: ComponentType): Matcher {
this.condition.component = componentType;
return this;
}
/**
*
*/
public withoutTag(): Matcher {
delete this.condition.tag;
return this;
}
/**
*
*/
public withoutName(): Matcher {
delete this.condition.name;
return this;
}
/**
*
*/
public withoutComponent(): Matcher {
delete this.condition.component;
return this;
}
/**
*
*/
public getCondition(): Readonly<QueryCondition> {
return {
all: [...this.condition.all],
any: [...this.condition.any],
none: [...this.condition.none],
tag: this.condition.tag,
name: this.condition.name,
component: this.condition.component
};
}
/**
*
*/
public isEmpty(): boolean {
return this.condition.all.length === 0 &&
this.condition.any.length === 0 &&
this.condition.none.length === 0 &&
this.condition.tag === undefined &&
this.condition.name === undefined &&
this.condition.component === undefined;
}
/**
*
*/
public reset(): Matcher {
this.condition.all.length = 0;
this.condition.any.length = 0;
this.condition.none.length = 0;
delete this.condition.tag;
delete this.condition.name;
delete this.condition.component;
return this;
}
/**
*
*/
public clone(): Matcher {
const cloned = new Matcher();
cloned.condition.all.push(...this.condition.all);
cloned.condition.any.push(...this.condition.any);
cloned.condition.none.push(...this.condition.none);
if (this.condition.tag !== undefined) {
cloned.condition.tag = this.condition.tag;
}
if (this.condition.name !== undefined) {
cloned.condition.name = this.condition.name;
}
if (this.condition.component !== undefined) {
cloned.condition.component = this.condition.component;
}
return cloned;
}
/**
*
*/
public toString(): string {
const parts: string[] = [];
if (this.condition.all.length > 0) {
parts.push(`all(${this.condition.all.map(t => getComponentTypeName(t)).join(', ')})`);
}
if (this.condition.any.length > 0) {
parts.push(`any(${this.condition.any.map(t => getComponentTypeName(t)).join(', ')})`);
}
if (this.condition.none.length > 0) {
parts.push(`none(${this.condition.none.map(t => getComponentTypeName(t)).join(', ')})`);
}
if (this.condition.tag !== undefined) {
parts.push(`tag(${this.condition.tag})`);
}
if (this.condition.name !== undefined) {
parts.push(`name(${this.condition.name})`);
}
if (this.condition.component !== undefined) {
parts.push(`component(${getComponentTypeName(this.condition.component)})`);
}
return `Matcher[${parts.join(' & ')}]`;
}
}