@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
262 lines (193 loc) • 6.25 kB
JavaScript
import { assert } from "../../../core/assert.js";
import { combine_hash } from "../../../core/collection/array/combine_hash.js";
import { computeIntegerArrayHash } from "../../../core/collection/array/computeIntegerArrayHash.js";
import { isArrayEqualStrict } from "../../../core/collection/array/isArrayEqualStrict.js";
import Vector2 from '../../../core/geom/Vector2.js';
class GridObstacle {
data = [1];
/**
* @readonly
* @type {Vector2}
*/
size = new Vector2(1, 1);
/**
*
* @param {number} w
* @param {number} h
*/
resize(w, h) {
assert.isNonNegativeInteger(w, 'w');
assert.isNonNegativeInteger(h, 'h');
const x1 = this.size.x;
const y1 = this.size.y;
const oldData = this.data;
const newData = new Uint8Array(w * h);
let i, j;
const iL = Math.min(x1, w);
const jL = Math.min(y1, h);
//copy
for (j = 0; j < jL; j++) {
const oJ = j * x1;
const nJ = j * w;
for (i = 0; i < iL; i++) {
newData[nJ + i] = oldData[oJ + i];
}
}
//set new property values
this.data = newData;
this.size.set(w, h);
}
/**
*
* @param {number} offsetX
* @param {number} offsetY
* @param {function(x:number, y:number, value:number, index:number)} visitor
* @param {*} [thisArg]
*/
traverseMask(offsetX, offsetY, visitor, thisArg) {
assert.isNumber(offsetX, 'offsetX');
assert.isNumber(offsetY, 'offsetY');
assert.isFunction(visitor, 'visitor');
const size = this.size;
const sX = size.x;
const sY = size.y;
const data = this.data;
let index = 0;
let i, j;
for (i = 0; i < sY; i++) {
for (j = 0; j < sX; j++) {
const value = data[index];
index++;
if (visitor.call(thisArg, j + offsetX, i + offsetY, value, index) === false) {
//stop traversal
return;
}
}
}
}
/**
*
* @param {number} x
* @param {number} y
* @returns {number}
*/
readPoint(x, y) {
assert.isNumber(x, 'x');
assert.isNumber(y, 'y');
assert.isInteger(x, 'x');
assert.isInteger(y, 'y');
const index = y * this.size.x + x;
return this.data[index];
}
/**
*
* @param {number} x
* @param {number} y
* @param {number} value
*/
writePoint(x, y, value) {
assert.isNonNegativeInteger(value, 'value');
assert.lessThanOrEqual(value, 255);
const index = y * this.size.x + x;
this.data[index] = value;
}
/**
*
* @param {number} x
* @param {number} y
* @returns {boolean}
*/
isPointWithin(x, y) {
assert.isNumber(x, 'x');
assert.isNumber(y, 'y');
const size = this.size;
const sX = size.x;
const sY = size.y;
return x >= 0 && x < sX && y >= 0 && y < sY;
}
/**
* Is a given point adjacent to a blocking cell?
* @param {number} x Obstacle-Local X position
* @param {number} y Obstacle-Local Y position
* @param {number[]} adjacencyMask Mask that defines adjacency, contains pairs of number for each X,Y coordinate offset from obstacle point
* @returns {boolean}
*/
isPointAdjacent(x, y, adjacencyMask) {
assert.isNumber(x, 'x');
assert.isNumber(y, 'y');
assert.defined(adjacencyMask, 'mask');
assert.notNull(adjacencyMask, 'mask');
assert.isArrayLike(adjacencyMask, 'mask');
const size = this.size;
const sX = size.x;
const sY = size.y;
const data = this.data;
const maskLength = adjacencyMask.length;
assert.isNonNegativeInteger(maskLength, 'maskLength');
assert.equal(maskLength % 2, 0, `maskLength must be a multiple of 2`);
for (let k = 0; k < maskLength; k += 2) {
const offsetX = adjacencyMask[k];
const offsetY = adjacencyMask[k + 1];
//reconstruct origin point within the grid
const aY = y - offsetY;
const aX = x - offsetX;
if (aX < 0 || aX >= sX || aY < 0 || aY >= sY) {
//origin point is outside of bounds
continue;
}
const index = aY * sX + aX;
const value = data[index];
if (value === 0) {
//non-obstructing
continue;
}
//found a matching adjacent point
return true;
}
//no matches
return false;
}
toJSON() {
return {
size: this.size.toJSON(),
data: Array.from(this.data) //make sure to force it to Array type for JSON serialization to work correctly
};
}
fromJSON({ size, data }) {
assert.isArrayLike(data, 'data');
this.size.fromJSON(size);
const sX = this.size.x;
const sY = this.size.y;
assert.equal(data.length, sX * sY, 'invalid array length');
this.data = new Uint8Array(sX * sY);
this.data.set(data, 0);
}
static fromJSON(j) {
const r = new GridObstacle();
r.fromJSON(j);
return r;
}
/**
*
* @returns {number}
*/
hash() {
return combine_hash(
this.size.hash(),
computeIntegerArrayHash(this.data, 0, this.data.length)
);
}
/**
*
* @param {GridObstacle} other
* @returns {boolean}
*/
equals(other) {
if (!this.size.equals(other.size)) {
return false;
}
return isArrayEqualStrict(this.data, other.data);
}
}
GridObstacle.typeName = "GridObstacle";
export default GridObstacle;