UNPKG

roguelike-pumpkin-patch

Version:
135 lines 5.63 kB
/** 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