HumanBreak/src/plugin/game/range.ts
2023-05-04 16:03:23 +08:00

101 lines
2.4 KiB
TypeScript

type RangeScanFn<C extends Partial<Loc>> = (
collection: Range<C>,
data: any
) => C[];
type InRangeFn<C extends Partial<Loc>> = (
collection: Range<C>,
data: any,
item: Partial<Loc>
) => boolean;
interface RangeType<C extends Partial<Loc>> {
scan: RangeScanFn<C>;
inRange: InRangeFn<C>;
}
export interface RangeCollection<I extends Partial<Loc>> {
list: I[];
range: Range<I>;
}
export class Range<C extends Partial<Loc>> {
collection: RangeCollection<C>;
cache: Record<string, any> = {};
static rangeType: Record<string, RangeType<Partial<Loc>>> = {};
constructor(collection: RangeCollection<C>) {
this.collection = collection;
}
/**
* 扫描 collection 中在范围内的物品
* @param type 范围类型
* @param data 范围数据
* @returns 在范围内的物品列表
*/
scan(type: string, data: any): C[] {
const t = Range.rangeType[type];
if (!t) {
throw new Error(`Unknown range type: ${type}.`);
}
return t.scan(this, data) as C[];
}
inRange(type: string, data: any, item: Partial<Loc>) {
const t = Range.rangeType[type];
if (!t) {
throw new Error(`Unknown range type: ${type}.`);
}
return t.inRange(this, data, item);
}
clearCache() {
this.cache = {};
}
static registerRangeType(
type: string,
scan: RangeScanFn<Partial<Loc>>,
inRange: InRangeFn<Partial<Loc>>
) {
Range.rangeType[type] = {
scan,
inRange
};
}
}
// ----- 默认的范围类型
// 方形区域
Range.registerRangeType(
'square',
(col, { x, y, d }) => {
const cache = (col.cache.square ??= {});
const index = `${x},${y},${d}`;
if (index in cache) return cache[index];
const list = col.collection.list;
const r = Math.floor(d);
return (cache[index] = list.filter(v => {
return (
core.has(v.x) &&
core.has(v.y) &&
Math.abs(v.x - x) <= r &&
Math.abs(v.y - y) <= r
);
}));
},
(col, { x, y, d }, item) => {
const r = Math.floor(d / 2);
return (
core.has(item.x) &&
core.has(item.y) &&
Math.abs(item.x - x) <= r &&
Math.abs(item.y - y) <= r
);
}
);