@phaserjs/phaser
Version:
142 lines (141 loc) • 3.93 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { GetLocalBounds } from "../../components/transform/GetLocalBounds";
export class SpatialHashGrid {
constructor(cellWidth, cellHeight, getBounds = GetLocalBounds) {
__publicField(this, "cellWidth");
__publicField(this, "cellHeight");
__publicField(this, "cells");
__publicField(this, "ids");
__publicField(this, "index");
__publicField(this, "getBounds");
this.cellWidth = Math.abs(cellWidth);
this.cellHeight = Math.abs(cellHeight);
this.cells = new Map();
this.ids = [];
this.index = 0;
this.getBounds = getBounds;
}
clear() {
this.cells.forEach((cell) => cell.clear());
this.cells.clear();
this.ids = [];
this.index = 0;
}
getX(x) {
return Math.floor(x / this.cellWidth);
}
getY(y) {
return Math.floor(y / this.cellHeight);
}
getXCeil(x) {
return Math.ceil(x / this.cellWidth);
}
getYCeil(y) {
return Math.ceil(y / this.cellHeight);
}
getKey(x, y) {
return `${this.getX(x)} ${this.getY(y)}`;
}
getGridKey(x, y) {
return `${x} ${y}`;
}
addToCell(id, gridX, gridY) {
const cells = this.cells;
const key = this.getGridKey(gridX, gridY);
if (cells.has(key)) {
cells.get(key).add(id);
} else {
cells.set(key, new Set([id]));
}
return key;
}
inView(x, y, width, height) {
return this.intersects(x, y, x + width, y + height);
}
intersects(left, top, right, bottom) {
const topLeftX = this.getX(left);
const topLeftY = this.getY(top);
const bottomRightX = this.getX(right);
const bottomRightY = this.getY(bottom);
const cells = this.cells;
let results = [];
if (topLeftX === bottomRightX && topLeftY === bottomRightY) {
const key = this.getGridKey(topLeftX, topLeftY);
if (cells.has(key)) {
results = [...cells.get(key)];
}
} else {
const width = bottomRightX - topLeftX + 1;
const height = bottomRightY - topLeftY + 1;
let gridX = topLeftX;
let gridY = topLeftY;
let placed = 0;
for (let i = 0; i < width * height; i++) {
const key = this.getGridKey(gridX, gridY);
if (cells.has(key)) {
results = results.concat(...cells.get(key));
}
gridX++;
placed++;
if (placed === width) {
gridX = topLeftX;
gridY++;
placed = 0;
}
}
}
const ids = this.ids;
results.sort((a, b) => {
return ids[a] - ids[b];
});
return new Set(results);
}
add(id) {
const { left, top, right, bottom } = this.getBounds(id);
const topLeftX = this.getX(left);
const topLeftY = this.getY(top);
const bottomRightX = this.getXCeil(right);
const bottomRightY = this.getYCeil(bottom);
const width = bottomRightX - topLeftX;
const height = bottomRightY - topLeftY;
this.ids[id] = this.index++;
if (width === 1 && height === 1) {
this.addToCell(id, topLeftX, topLeftY);
return;
}
let gridX = topLeftX;
let gridY = topLeftY;
let placed = 0;
for (let i = 0; i < width * height; i++) {
this.addToCell(id, gridX, gridY);
gridX++;
placed++;
if (placed === width) {
gridX = topLeftX;
gridY++;
placed = 0;
}
}
}
update(id) {
this.remove(id);
this.add(id);
}
has(id) {
return !!this.ids[id];
}
getAll() {
return this.ids.filter((index, id) => id !== void 0);
}
remove(id) {
if (this.has(id)) {
this.cells.forEach((cell) => cell.delete(id));
this.ids[id] = void 0;
}
}
}