roguelike-pumpkin-patch
Version:
A roguelike development library in JavaScript.
135 lines • 5.63 kB
JavaScript
/** Field of view */
var FOV = /** @class */ (function () {
/** Accepts a callback function to determine if a location is seethrough */
function FOV(canSee, range) {
this.canSee = canSee;
this.range = range ? range : 8;
}
;
/** Do the FOV calculation */
FOV.prototype.look = function (position, lookRangeOverride) {
var range = (lookRangeOverride) ? lookRangeOverride : this.range;
// See the starting location (hooray! Great start)
this.canSee(position);
// const lookTiles:Array<Tile> = [];
var shadows = [];
var newShadows = [];
// From nearby to far away
var i = 0;
var j = 0;
for (var distance = 1; distance <= range; distance++) {
// Get square shell around position
for (var side = 0; side < 4; side++) {
for (var edge = -distance; edge <= distance; edge++) {
if (side === 0) {
i = edge;
j = distance;
}
else if (side === 1) {
j = edge;
i = distance;
}
else if (side === 2) {
i = edge;
j = -distance;
}
else {
j = edge;
i = -distance;
}
var lookPos = [position[0] + i, position[1] + j];
var dist = this.distance(position, lookPos);
// Out of range? Skip.
if (dist > range) {
continue;
}
// In shadows? Skip.
var angleTo = this.angleTo(position, lookPos);
var angularSize = this.angularSize(position, lookPos) / 2;
var inShadows = false;
if (this.isInShadows(angleTo, shadows) &&
this.isInShadows(angleTo + angularSize, shadows) &&
this.isInShadows(angleTo - angularSize, shadows)) {
inShadows = true;
}
// Now, test if we can see through the tile
if (inShadows || !this.canSee(lookPos)) {
// Square is opaque! Add its shadow
newShadows.push({
startAngle: angleTo - angularSize,
endAngle: angleTo + angularSize
});
}
}
}
// Add newShadows to shadows
while (newShadows.length > 0) {
// shadows.push(newShadows.pop());
this.combineShadow(shadows, newShadows.pop());
}
// Check if we should call it quits
if (shadows.length === 1 && shadows[0].endAngle - shadows[0].startAngle >= 360) {
return;
}
}
};
;
/** Get angle a tile resides in
* This ranges from -180 to 180, so be careful
*/
FOV.prototype.angleTo = function (startPosition, endPosition) {
var y = endPosition[1] - startPosition[1];
var x = endPosition[0] - startPosition[0];
var angle = 180 * Math.atan2(y, x) / Math.PI;
return (angle >= 0) ? angle : angle + 360;
};
;
/** Get angular size of a square */
FOV.prototype.angularSize = function (startPosition, endPosition) {
var distance = this.distance(startPosition, endPosition);
return 360 * Math.atan(1 / (2 * distance)) / Math.PI;
};
;
/** Get distance */
FOV.prototype.distance = function (startPosition, endPosition) {
return Math.sqrt(Math.pow((endPosition[1] - startPosition[1]), 2) + Math.pow((endPosition[0] - startPosition[0]), 2));
};
/** Check if in shadows */
FOV.prototype.isInShadows = function (angle, shadows) {
var negAngle = angle - 360;
for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
var shadow = shadows_1[_i];
if ((angle <= shadow.endAngle && angle >= shadow.startAngle) || (negAngle <= shadow.endAngle && negAngle >= shadow.startAngle)) {
return true;
}
}
return false;
};
/** Add a shadow to the shadow array */
FOV.prototype.combineShadow = function (shadows, newShadow) {
var overLapArr = [];
for (var i = 0; i < shadows.length; i++) {
var shadow = shadows[i];
// Check if they overlap
if (newShadow.startAngle < shadow.endAngle && newShadow.endAngle > shadow.startAngle) {
newShadow.startAngle = Math.min(shadow.startAngle, newShadow.startAngle);
newShadow.endAngle = Math.max(shadow.endAngle, newShadow.endAngle);
overLapArr.push(i);
}
}
if (overLapArr.length > 0) {
var mainShadow = shadows[overLapArr.shift()];
mainShadow.startAngle = newShadow.startAngle;
mainShadow.endAngle = newShadow.endAngle;
for (var i = overLapArr.length - 1; i >= 0; i--) {
shadows.splice(overLapArr[i], 1);
}
}
else {
shadows.push(newShadow);
}
};
return FOV;
}());
export default FOV;
//# sourceMappingURL=FOV.js.map