You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
42 lines
1.5 KiB
42 lines
1.5 KiB
|
3 weeks ago
|
import type { EntityId } from 'db://assets/mx/module/ecs/EntityId';
|
||
|
|
import type { EcsComponent, ComponentCtor } from 'db://assets/mx/module/ecs/Component';
|
||
|
|
|
||
|
|
/** 组件存储桶的最小接口(结构类型,避免与 World 循环 import) */
|
||
|
|
export interface IComponentStorage<A extends EcsComponent> {
|
||
|
|
forEach(fn: (id: EntityId, comp: A) => void): void;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 单组件查询视图 */
|
||
|
|
export class View1<A extends EcsComponent> {
|
||
|
|
constructor(
|
||
|
|
private readonly _storage: IComponentStorage<A>,
|
||
|
|
private readonly _isAlive: (id: EntityId) => boolean,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
/** 遍历所有拥有该组件的存活实体 */
|
||
|
|
forEach(fn: (id: EntityId, a: A) => void): void {
|
||
|
|
this._storage.forEach((id, a) => {
|
||
|
|
if (this._isAlive(id)) fn(id, a);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 双组件查询视图(按 ctorA 桶遍历 + 过滤 ctorB) */
|
||
|
|
export class View2<A extends EcsComponent, B extends EcsComponent> {
|
||
|
|
constructor(
|
||
|
|
private readonly _storageA: IComponentStorage<A>,
|
||
|
|
private readonly _ctorB: ComponentCtor<B>,
|
||
|
|
private readonly _getComponent: (id: EntityId, ctor: ComponentCtor<B>) => B | undefined,
|
||
|
|
private readonly _isAlive: (id: EntityId) => boolean,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
/** 遍历所有同时拥有两个组件的存活实体 */
|
||
|
|
forEach(fn: (id: EntityId, a: A, b: B) => void): void {
|
||
|
|
this._storageA.forEach((id, a) => {
|
||
|
|
if (!this._isAlive(id)) return;
|
||
|
|
const b = this._getComponent(id, this._ctorB);
|
||
|
|
if (b) fn(id, a, b);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|