621 lines
26 KiB
JavaScript
621 lines
26 KiB
JavaScript
/// <reference path="ObjectMakr-0.2.2.ts" />
|
|
var QuadsKeepr;
|
|
(function (QuadsKeepr_1) {
|
|
"use strict";
|
|
/**
|
|
* Quadrant-based collision detection. A grid structure of Quadrants is kept,
|
|
* with Things placed within quadrants they intersect. Each Quadrant knows which
|
|
* Things are in it, and each Thing knows its quadrants. Operations are
|
|
* available to shift quadrants horizontally or vertically and add/remove rows
|
|
* and columns.
|
|
*/
|
|
var QuadsKeepr = (function () {
|
|
/**
|
|
* @param {IQuadsKeeprSettings} settings
|
|
*/
|
|
function QuadsKeepr(settings) {
|
|
if (!settings) {
|
|
throw new Error("No settings object given to QuadsKeepr.");
|
|
}
|
|
if (!settings.ObjectMaker) {
|
|
throw new Error("No ObjectMaker given to QuadsKeepr.");
|
|
}
|
|
if (!settings.numRows) {
|
|
throw new Error("No numRows given to QuadsKeepr.");
|
|
}
|
|
if (!settings.numCols) {
|
|
throw new Error("No numCols given to QuadsKeepr.");
|
|
}
|
|
if (!settings.quadrantWidth) {
|
|
throw new Error("No quadrantWidth given to QuadsKeepr.");
|
|
}
|
|
if (!settings.quadrantHeight) {
|
|
throw new Error("No quadrantHeight given to QuadsKeepr.");
|
|
}
|
|
if (!settings.groupNames) {
|
|
throw new Error("No groupNames given to QuadsKeepr.");
|
|
}
|
|
this.ObjectMaker = settings.ObjectMaker;
|
|
this.numRows = settings.numRows | 0;
|
|
this.numCols = settings.numCols | 0;
|
|
this.quadrantWidth = settings.quadrantWidth | 0;
|
|
this.quadrantHeight = settings.quadrantHeight | 0;
|
|
this.groupNames = settings.groupNames;
|
|
this.onAdd = settings.onAdd;
|
|
this.onRemove = settings.onRemove;
|
|
this.startLeft = settings.startLeft | 0;
|
|
this.startTop = settings.startTop | 0;
|
|
this.keyTop = settings.keyTop || "top";
|
|
this.keyLeft = settings.keyLeft || "left";
|
|
this.keyBottom = settings.keyBottom || "bottom";
|
|
this.keyRight = settings.keyRight || "right";
|
|
this.keyNumQuads = settings.keyNumQuads || "numquads";
|
|
this.keyQuadrants = settings.keyQuadrants || "quadrants";
|
|
this.keyChanged = settings.keyChanged || "changed";
|
|
this.keyToleranceX = settings.keyToleranceX || "tolx";
|
|
this.keyToleranceY = settings.keyToleranceY || "toly";
|
|
this.keyGroupName = settings.keyGroupName || "group";
|
|
this.keyOffsetX = settings.keyOffsetX;
|
|
this.keyOffsetY = settings.keyOffsetY;
|
|
}
|
|
/* Simple gets
|
|
*/
|
|
/**
|
|
* @return {Object} The listing of Quadrants grouped by row.
|
|
*/
|
|
QuadsKeepr.prototype.getQuadrantRows = function () {
|
|
return this.quadrantRows;
|
|
};
|
|
/**
|
|
* @return {Object} The listing of Quadrants grouped by column.
|
|
*/
|
|
QuadsKeepr.prototype.getQuadrantCols = function () {
|
|
return this.quadrantCols;
|
|
};
|
|
/**
|
|
* @return {Number} How many Quadrant rows there are.
|
|
*/
|
|
QuadsKeepr.prototype.getNumRows = function () {
|
|
return this.numRows;
|
|
};
|
|
/**
|
|
* @return {Number} How many Quadrant columns there are.
|
|
*/
|
|
QuadsKeepr.prototype.getNumCols = function () {
|
|
return this.numCols;
|
|
};
|
|
/**
|
|
* @return {Number} How wide each Quadrant is.
|
|
*/
|
|
QuadsKeepr.prototype.getQuadrantWidth = function () {
|
|
return this.quadrantWidth;
|
|
};
|
|
/**
|
|
* @return {Number} How high each Quadrant is.
|
|
*/
|
|
QuadsKeepr.prototype.getQuadrantHeight = function () {
|
|
return this.quadrantHeight;
|
|
};
|
|
/* Quadrant updates
|
|
*/
|
|
/**
|
|
* Completely resets all Quadrants. The grid structure of rows and columns
|
|
* is remade according to startLeft and startTop, and newly created
|
|
* Quadrants pushed into it.
|
|
*/
|
|
QuadsKeepr.prototype.resetQuadrants = function () {
|
|
var left = this.startLeft, top = this.startTop, quadrant, i, j;
|
|
this.top = this.startTop;
|
|
this.right = this.startLeft + this.quadrantWidth * this.numCols;
|
|
this.bottom = this.startTop + this.quadrantHeight * this.numRows;
|
|
this.left = this.startLeft;
|
|
this.quadrantRows = [];
|
|
this.quadrantCols = [];
|
|
this.offsetX = 0;
|
|
this.offsetY = 0;
|
|
for (i = 0; i < this.numRows; i += 1) {
|
|
this.quadrantRows.push({
|
|
"left": this.startLeft,
|
|
"top": top,
|
|
"quadrants": []
|
|
});
|
|
top += this.quadrantHeight;
|
|
}
|
|
for (j = 0; j < this.numCols; j += 1) {
|
|
this.quadrantCols.push({
|
|
"left": left,
|
|
"top": this.startTop,
|
|
"quadrants": []
|
|
});
|
|
left += this.quadrantWidth;
|
|
}
|
|
top = this.startTop;
|
|
for (i = 0; i < this.numRows; i += 1) {
|
|
left = this.startLeft;
|
|
for (j = 0; j < this.numCols; j += 1) {
|
|
quadrant = this.createQuadrant(left, top);
|
|
this.quadrantRows[i].quadrants.push(quadrant);
|
|
this.quadrantCols[j].quadrants.push(quadrant);
|
|
left += this.quadrantWidth;
|
|
}
|
|
top += this.quadrantHeight;
|
|
}
|
|
if (this.onAdd) {
|
|
this.onAdd("xInc", this.top, this.right, this.bottom, this.left);
|
|
}
|
|
};
|
|
/**
|
|
* Shifts each Quadrant horizontally and vertically, along with the row and
|
|
* column containers. Offsets are adjusted to check for row or column
|
|
* deletion and insertion.
|
|
*
|
|
* @param {Number} dx How much to shfit horizontally (will be rounded).
|
|
* @param {Number} dy How much to shift vertically (will be rounded).
|
|
*/
|
|
QuadsKeepr.prototype.shiftQuadrants = function (dx, dy) {
|
|
if (dx === void 0) { dx = 0; }
|
|
if (dy === void 0) { dy = 0; }
|
|
var row, col;
|
|
dx = dx | 0;
|
|
dy = dy | 0;
|
|
this.offsetX += dx;
|
|
this.offsetY += dy;
|
|
this.top += dy;
|
|
this.right += dx;
|
|
this.bottom += dy;
|
|
this.left += dx;
|
|
for (row = 0; row < this.numRows; row += 1) {
|
|
this.quadrantRows[row].left += dx;
|
|
this.quadrantRows[row].top += dy;
|
|
}
|
|
for (col = 0; col < this.numCols; col += 1) {
|
|
this.quadrantCols[col].left += dx;
|
|
this.quadrantCols[col].top += dy;
|
|
}
|
|
for (row = 0; row < this.numRows; row += 1) {
|
|
for (col = 0; col < this.numCols; col += 1) {
|
|
this.shiftQuadrant(this.quadrantRows[row].quadrants[col], dx, dy);
|
|
}
|
|
}
|
|
this.adjustOffsets();
|
|
};
|
|
/**
|
|
* Adds a QuadrantRow to the end of the quadrantRows Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onAdd
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.pushQuadrantRow = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
var row = this.createQuadrantRow(this.left, this.bottom), i;
|
|
this.numRows += 1;
|
|
this.quadrantRows.push(row);
|
|
for (i = 0; i < this.quadrantCols.length; i += 1) {
|
|
this.quadrantCols[i].quadrants.push(row.quadrants[i]);
|
|
}
|
|
this.bottom += this.quadrantHeight;
|
|
if (callUpdate && this.onAdd) {
|
|
this.onAdd("yInc", this.bottom, this.right, this.bottom - this.quadrantHeight, this.left);
|
|
}
|
|
return row;
|
|
};
|
|
/**
|
|
* Adds a QuadrantCol to the end of the quadrantCols Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onAdd
|
|
* trigger with the new col's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.pushQuadrantCol = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
var col = this.createQuadrantCol(this.right, this.top), i;
|
|
this.numCols += 1;
|
|
this.quadrantCols.push(col);
|
|
for (i = 0; i < this.quadrantRows.length; i += 1) {
|
|
this.quadrantRows[i].quadrants.push(col.quadrants[i]);
|
|
}
|
|
this.right += this.quadrantWidth;
|
|
if (callUpdate && this.onAdd) {
|
|
this.onAdd("xInc", this.top, this.right - this.offsetY, this.bottom, this.right - this.quadrantWidth - this.offsetY);
|
|
}
|
|
return col;
|
|
};
|
|
/**
|
|
* Removes the last QuadrantRow from the end of the quadrantRows Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onRemove
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.popQuadrantRow = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
for (var i = 0; i < this.quadrantCols.length; i += 1) {
|
|
this.quadrantCols[i].quadrants.pop();
|
|
}
|
|
this.numRows -= 1;
|
|
this.quadrantRows.pop();
|
|
if (callUpdate && this.onRemove) {
|
|
this.onRemove("yInc", this.bottom, this.right, this.bottom - this.quadrantHeight, this.left);
|
|
}
|
|
this.bottom -= this.quadrantHeight;
|
|
};
|
|
/**
|
|
* Removes the last QuadrantCol from the end of the quadrantCols Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onRemove
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.popQuadrantCol = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
for (var i = 0; i < this.quadrantRows.length; i += 1) {
|
|
this.quadrantRows[i].quadrants.pop();
|
|
}
|
|
this.numCols -= 1;
|
|
this.quadrantCols.pop();
|
|
if (callUpdate && this.onRemove) {
|
|
this.onRemove("xDec", this.top, this.right - this.offsetY, this.bottom, this.right - this.quadrantWidth - this.offsetY);
|
|
}
|
|
this.right -= this.quadrantWidth;
|
|
};
|
|
/**
|
|
* Adds a QuadrantRow to the beginning of the quadrantRows Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onAdd
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.unshiftQuadrantRow = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
var row = this.createQuadrantRow(this.left, this.top - this.quadrantHeight), i;
|
|
this.numRows += 1;
|
|
this.quadrantRows.unshift(row);
|
|
for (i = 0; i < this.quadrantCols.length; i += 1) {
|
|
this.quadrantCols[i].quadrants.unshift(row.quadrants[i]);
|
|
}
|
|
this.top -= this.quadrantHeight;
|
|
if (callUpdate && this.onAdd) {
|
|
this.onAdd("yDec", this.top, this.right, this.top + this.quadrantHeight, this.left);
|
|
}
|
|
return row;
|
|
};
|
|
/**
|
|
* Adds a QuadrantCol to the beginning of the quadrantCols Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onAdd
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.unshiftQuadrantCol = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
var col = this.createQuadrantCol(this.left - this.quadrantWidth, this.top), i;
|
|
this.numCols += 1;
|
|
this.quadrantCols.unshift(col);
|
|
for (i = 0; i < this.quadrantRows.length; i += 1) {
|
|
this.quadrantRows[i].quadrants.unshift(col.quadrants[i]);
|
|
}
|
|
this.left -= this.quadrantWidth;
|
|
if (callUpdate && this.onAdd) {
|
|
this.onAdd("xDec", this.top, this.left, this.bottom, this.left + this.quadrantWidth);
|
|
}
|
|
return col;
|
|
};
|
|
/**
|
|
* Removes a QuadrantRow from the beginning of the quadrantRows Array.
|
|
*
|
|
* @param {Boolean} [callUpdate] Whether this should call the onAdd
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.shiftQuadrantRow = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
for (var i = 0; i < this.quadrantCols.length; i += 1) {
|
|
this.quadrantCols[i].quadrants.shift();
|
|
}
|
|
this.numRows -= 1;
|
|
this.quadrantRows.pop();
|
|
if (callUpdate && this.onRemove) {
|
|
this.onRemove("yInc", this.top, this.right, this.top + this.quadrantHeight, this.left);
|
|
}
|
|
this.top += this.quadrantHeight;
|
|
};
|
|
/**
|
|
* Removes a QuadrantCol from the beginning of the quadrantCols Array.
|
|
*
|
|
* @param {Boolean} callUpdate Whether this should call the onAdd
|
|
* trigger with the new row's bounding box.
|
|
*/
|
|
QuadsKeepr.prototype.shiftQuadrantCol = function (callUpdate) {
|
|
if (callUpdate === void 0) { callUpdate = false; }
|
|
for (var i = 0; i < this.quadrantRows.length; i += 1) {
|
|
this.quadrantRows[i].quadrants.shift();
|
|
}
|
|
this.numCols -= 1;
|
|
this.quadrantCols.pop();
|
|
if (callUpdate && this.onRemove) {
|
|
this.onRemove("xInc", this.top, this.left + this.quadrantWidth, this.bottom, this.left);
|
|
}
|
|
this.left += this.quadrantWidth;
|
|
};
|
|
/* Thing manipulations
|
|
*/
|
|
/**
|
|
* Determines the Quadrants for an entire Array of Things. This is done by
|
|
* wiping each quadrant's memory of that Array's group type and determining
|
|
* each Thing's quadrants.
|
|
*
|
|
* @param {String} group The name of the group to have Quadrants determined.
|
|
* @param {Thing[]} things The listing of Things in that group.
|
|
*/
|
|
QuadsKeepr.prototype.determineAllQuadrants = function (group, things) {
|
|
var row, col;
|
|
for (row = 0; row < this.numRows; row += 1) {
|
|
for (col = 0; col < this.numCols; col += 1) {
|
|
this.quadrantRows[row].quadrants[col].numthings[group] = 0;
|
|
}
|
|
}
|
|
things.forEach(this.determineThingQuadrants.bind(this));
|
|
};
|
|
/**
|
|
* Determines the Quadrants for a single Thing. The starting row and column
|
|
* indices are calculated so every Quadrant within them should contain the
|
|
* Thing. In the process, its old Quadrants and new Quadrants are marked as
|
|
* changed if it was.
|
|
*
|
|
* @param {Thing} thing
|
|
*/
|
|
QuadsKeepr.prototype.determineThingQuadrants = function (thing) {
|
|
var group = thing[this.keyGroupName], rowStart = this.findQuadrantRowStart(thing), colStart = this.findQuadrantColStart(thing), rowEnd = this.findQuadrantRowEnd(thing), colEnd = this.findQuadrantColEnd(thing), row, col;
|
|
// Mark each of the Thing's Quadrants as changed
|
|
// This is done first because the old Quadrants are changed
|
|
if (thing[this.keyChanged]) {
|
|
this.markThingQuadrantsChanged(thing);
|
|
}
|
|
// The Thing no longer has any Quadrants: rebuild them!
|
|
thing[this.keyNumQuads] = 0;
|
|
for (row = rowStart; row <= rowEnd; row += 1) {
|
|
for (col = colStart; col <= colEnd; col += 1) {
|
|
this.setThingInQuadrant(thing, this.quadrantRows[row].quadrants[col], group);
|
|
}
|
|
}
|
|
// The thing is no longer considered changed, since quadrants know it
|
|
thing[this.keyChanged] = false;
|
|
};
|
|
/**
|
|
* Sets a Thing to be inside a Quadrant. The two are marked so they can
|
|
* recognize each other's existence later.
|
|
*
|
|
* @param {Thing} thing
|
|
* @param {Quadrant} quadrant
|
|
* @param {String} group The grouping under which the Quadrant should
|
|
* store the Thing.
|
|
*/
|
|
QuadsKeepr.prototype.setThingInQuadrant = function (thing, quadrant, group) {
|
|
// Mark the Quadrant in the Thing
|
|
thing[this.keyQuadrants][thing[this.keyNumQuads]] = quadrant;
|
|
thing[this.keyNumQuads] += 1;
|
|
// Mark the Thing in the Quadrant
|
|
quadrant.things[group][quadrant.numthings[group]] = thing;
|
|
quadrant.numthings[group] += 1;
|
|
// If necessary, mark the Quadrant as changed
|
|
if (thing[this.keyChanged]) {
|
|
quadrant.changed = true;
|
|
}
|
|
};
|
|
/* Internal rearranging
|
|
*/
|
|
/**
|
|
* Adjusts the offset measurements by checking if rows or columns have gone
|
|
* over the limit, which requires rows or columns be removed and new ones
|
|
* added.
|
|
*/
|
|
QuadsKeepr.prototype.adjustOffsets = function () {
|
|
// Quadrant shift: add to the right
|
|
while (-this.offsetX > this.quadrantWidth) {
|
|
this.shiftQuadrantCol(true);
|
|
this.pushQuadrantCol(true);
|
|
this.offsetX += this.quadrantWidth;
|
|
}
|
|
// Quadrant shift: add to the left
|
|
while (this.offsetX > this.quadrantWidth) {
|
|
this.popQuadrantCol(true);
|
|
this.unshiftQuadrantCol(true);
|
|
this.offsetX -= this.quadrantWidth;
|
|
}
|
|
// Quadrant shift: add to the bottom
|
|
while (-this.offsetY > this.quadrantHeight) {
|
|
this.unshiftQuadrantRow(true);
|
|
this.pushQuadrantRow(true);
|
|
this.offsetY += this.quadrantHeight;
|
|
}
|
|
// Quadrant shift: add to the top
|
|
while (this.offsetY > this.quadrantHeight) {
|
|
this.popQuadrantRow(true);
|
|
this.unshiftQuadrantRow(true);
|
|
this.offsetY -= this.quadrantHeight;
|
|
}
|
|
};
|
|
/**
|
|
* Shifts a Quadrant horizontally and vertically.
|
|
*
|
|
* @param {Number} dx
|
|
* @param {Number} dy
|
|
*/
|
|
QuadsKeepr.prototype.shiftQuadrant = function (quadrant, dx, dy) {
|
|
quadrant.top += dy;
|
|
quadrant.right += dx;
|
|
quadrant.bottom += dy;
|
|
quadrant.left += dx;
|
|
quadrant.changed = true;
|
|
};
|
|
/* Quadrant placements
|
|
*/
|
|
/**
|
|
* Creates a new Quadrant using the internal ObjectMaker. The Quadrant's
|
|
* sizing and position are set, along with a canvas element for rendering.
|
|
*
|
|
* @param {Number} left The horizontal displacement of the Quadrant.
|
|
* @param {Number} top The vertical displacement of the Quadrant.
|
|
* @return {Quadrant}
|
|
*/
|
|
QuadsKeepr.prototype.createQuadrant = function (left, top) {
|
|
var quadrant = this.ObjectMaker.make("Quadrant"), i;
|
|
quadrant.changed = true;
|
|
quadrant.things = {};
|
|
quadrant.numthings = {};
|
|
for (i = 0; i < this.groupNames.length; i += 1) {
|
|
quadrant.things[this.groupNames[i]] = [];
|
|
quadrant.numthings[this.groupNames[i]] = 0;
|
|
}
|
|
quadrant.left = left;
|
|
quadrant.top = top;
|
|
quadrant.right = left + this.quadrantWidth;
|
|
quadrant.bottom = top + this.quadrantHeight;
|
|
quadrant.canvas = this.createCanvas(this.quadrantWidth, this.quadrantHeight);
|
|
// A cast here is needed because older versions of TypeScript / tslint
|
|
// may still see canvas.getContext("2d") as returning a WebGLRenderingContext
|
|
quadrant.context = quadrant.canvas.getContext("2d");
|
|
return quadrant;
|
|
};
|
|
/**
|
|
* Creates a QuadrantRow, with length determined by numCols.
|
|
*
|
|
* @param {Number} left The initial horizontal displacement of the col.
|
|
* @param {Number} top The vertical displacement of the col.
|
|
* @return {QuadrantRow[]}
|
|
*/
|
|
QuadsKeepr.prototype.createQuadrantRow = function (left, top) {
|
|
if (left === void 0) { left = 0; }
|
|
if (top === void 0) { top = 0; }
|
|
var row = {
|
|
"left": left,
|
|
"top": top,
|
|
"quadrants": []
|
|
}, i;
|
|
for (i = 0; i < this.numCols; i += 1) {
|
|
row.quadrants.push(this.createQuadrant(left, top));
|
|
left += this.quadrantWidth;
|
|
}
|
|
return row;
|
|
};
|
|
/**
|
|
* Creates a QuadrantCol, with length determined by numRow.
|
|
*
|
|
* @param {Number} left The horizontal displacement of the col.
|
|
* @param {Number} top The initial vertical displacement of the col.
|
|
* @return {QuadrantRow[]}
|
|
*/
|
|
QuadsKeepr.prototype.createQuadrantCol = function (left, top) {
|
|
var col = {
|
|
"left": left,
|
|
"top": top,
|
|
"quadrants": []
|
|
}, i;
|
|
for (i = 0; i < this.numRows; i += 1) {
|
|
col.quadrants.push(this.createQuadrant(left, top));
|
|
top += this.quadrantHeight;
|
|
}
|
|
return col;
|
|
};
|
|
/* Position utilities
|
|
*/
|
|
/**
|
|
* @param {Thing} thing
|
|
* @return {Number} The Thing's top position, accounting for vertical
|
|
* offset if needed.
|
|
*/
|
|
QuadsKeepr.prototype.getTop = function (thing) {
|
|
if (this.keyOffsetY) {
|
|
return thing[this.keyTop] - Math.abs(thing[this.keyOffsetY]);
|
|
}
|
|
else {
|
|
return thing[this.keyTop];
|
|
}
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @return {Number} The Thing's right position, accounting for horizontal
|
|
* offset if needed.
|
|
*/
|
|
QuadsKeepr.prototype.getRight = function (thing) {
|
|
if (this.keyOffsetX) {
|
|
return thing[this.keyRight] + Math.abs(thing[this.keyOffsetX]);
|
|
}
|
|
else {
|
|
return thing[this.keyRight];
|
|
}
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @return {Number} The Thing's bottom position, accounting for vertical
|
|
* offset if needed.
|
|
*/
|
|
QuadsKeepr.prototype.getBottom = function (thing) {
|
|
if (this.keyOffsetX) {
|
|
return thing[this.keyBottom] + Math.abs(thing[this.keyOffsetY]);
|
|
}
|
|
else {
|
|
return thing[this.keyBottom];
|
|
}
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @return {Number} The Thing's left position, accounting for horizontal
|
|
* offset if needed.
|
|
*/
|
|
QuadsKeepr.prototype.getLeft = function (thing) {
|
|
if (this.keyOffsetX) {
|
|
return thing[this.keyLeft] - Math.abs(thing[this.keyOffsetX]);
|
|
}
|
|
else {
|
|
return thing[this.keyLeft];
|
|
}
|
|
};
|
|
/**
|
|
* Marks all Quadrants a Thing is contained within as changed.
|
|
*/
|
|
QuadsKeepr.prototype.markThingQuadrantsChanged = function (thing) {
|
|
for (var i = 0; i < thing[this.keyNumQuads]; i += 1) {
|
|
thing[this.keyQuadrants][i].changed = true;
|
|
}
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @param {Number} The index of the first row the Thing is inside.
|
|
*/
|
|
QuadsKeepr.prototype.findQuadrantRowStart = function (thing) {
|
|
return Math.max(Math.floor((this.getTop(thing) - this.top) / this.quadrantHeight), 0);
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @param {Number} The index of the last row the Thing is inside.
|
|
*/
|
|
QuadsKeepr.prototype.findQuadrantRowEnd = function (thing) {
|
|
return Math.min(Math.floor((this.getBottom(thing) - this.top) / this.quadrantHeight), this.numRows - 1);
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @param {Number} The index of the first column the Thing is inside.
|
|
*/
|
|
QuadsKeepr.prototype.findQuadrantColStart = function (thing) {
|
|
return Math.max(Math.floor((this.getLeft(thing) - this.left) / this.quadrantWidth), 0);
|
|
};
|
|
/**
|
|
* @param {Thing} thing
|
|
* @param {Number} The index of the last column the Thing is inside.
|
|
*/
|
|
QuadsKeepr.prototype.findQuadrantColEnd = function (thing) {
|
|
return Math.min(Math.floor((this.getRight(thing) - this.left) / this.quadrantWidth), this.numCols - 1);
|
|
};
|
|
/**
|
|
* Creates a new canvas element of the given size.
|
|
*
|
|
* @param {Number} width How wide the canvas should be.
|
|
* @param {Number} height How tall the canvas should be.
|
|
* @return {HTMLCanvasElement}
|
|
*/
|
|
QuadsKeepr.prototype.createCanvas = function (width, height) {
|
|
var canvas = document.createElement("canvas");
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
return canvas;
|
|
};
|
|
return QuadsKeepr;
|
|
})();
|
|
QuadsKeepr_1.QuadsKeepr = QuadsKeepr;
|
|
})(QuadsKeepr || (QuadsKeepr = {}));
|