UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

262 lines (193 loc) • 6.25 kB
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;