isaacscript-common
Version:
Helper functions and features for IsaacScript mods.
150 lines (149 loc) • 5.81 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.clamp = clamp;
exports.getAngleDifference = getAngleDifference;
exports.getCircleDiscretizedPoints = getCircleDiscretizedPoints;
exports.inRectangle = inRectangle;
exports.isCircleIntersectingRectangle = isCircleIntersectingRectangle;
exports.isEven = isEven;
exports.isOdd = isOdd;
exports.lerp = lerp;
exports.lerpAngleDegrees = lerpAngleDegrees;
exports.round = round;
exports.sign = sign;
exports.splitNumber = splitNumber;
exports.tanh = tanh;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const direction_1 = require("./direction");
/**
* Helper function to normalize a number, ensuring that it is within a certain range.
*
* - If `num` is less than `min`, then it will be clamped to `min`.
* - If `num` is greater than `max`, then it will be clamped to `max`.
*/
function clamp(num, min, max) {
return Math.max(min, Math.min(num, max));
}
function getAngleDifference(angle1, angle2) {
const subtractedAngle = angle1 - angle2;
return ((subtractedAngle + 180) % 360) - 180;
}
/**
* Helper function to get an array of equidistant points on the circumference around a circle.
* Useful for equally distributing things in a circle pattern.
*
* @param centerPos A position that represents the center of the center to get the points from.
* @param radius The length of the radius of the circle.
* @param numPoints The number of points on the circumference of the circle to get.
* @param xMultiplier An optional multiplier to get the points around an oval. Default is 1.
* @param yMultiplier An optional multiplier to get the points around an oval. Default is 1.
* @param initialDirection By default, the first point on the circle will be on the top center, but
* this can be optionally changed by specifying this argument.
*/
function getCircleDiscretizedPoints(centerPos, radius, numPoints, xMultiplier = 1, yMultiplier = 1, initialDirection = isaac_typescript_definitions_1.Direction.UP) {
const vector = (0, direction_1.directionToVector)(initialDirection);
const initialPosition = vector.mul(radius);
const positions = [];
for (let i = 0; i < numPoints; i++) {
const rotatedPosition = initialPosition.Rotated((i * 360) / numPoints);
rotatedPosition.X *= xMultiplier;
rotatedPosition.Y *= yMultiplier;
const positionFromCenter = centerPos.add(rotatedPosition);
positions.push(positionFromCenter);
}
return positions;
}
/**
* Helper function to check if a given position is within a given rectangle.
*
* This is an inclusive check, meaning that it will return true if the position is on the border of
* the rectangle.
*/
function inRectangle(position, topLeft, bottomRight) {
return (position.X >= topLeft.X
&& position.X <= bottomRight.X
&& position.Y >= topLeft.Y
&& position.Y <= bottomRight.Y);
}
/**
* From: https://www.geeksforgeeks.org/check-if-any-point-overlaps-the-given-circle-and-rectangle/
*/
function isCircleIntersectingRectangle(circleCenter, circleRadius, rectangleTopLeft, rectangleBottomRight) {
const nearestX = Math.max(rectangleTopLeft.X, Math.min(circleCenter.X, rectangleBottomRight.X));
const nearestY = Math.max(rectangleTopLeft.Y, Math.min(circleCenter.Y, rectangleBottomRight.Y));
const nearestPointToCircleOnRectangle = Vector(nearestX, nearestY);
const distanceToCenterOfCircle = nearestPointToCircleOnRectangle.Distance(circleCenter);
return distanceToCenterOfCircle <= circleRadius;
}
function isEven(num) {
// This is benchmarked to be faster than using the modulus operator by 3%.
return (num & 1) === 0;
}
function isOdd(num) {
// This is benchmarked to be faster than using the modulus operator by 3%.
return (num & 1) === 1;
}
function lerp(a, b, pos) {
return a + (b - a) * pos;
}
function lerpAngleDegrees(aStart, aEnd, percent) {
return aStart + getAngleDifference(aStart, aEnd) * percent;
}
/**
* If rounding fails, this function returns 0.
*
* From: http://lua-users.org/wiki/SimpleRound
*
* @param num The number to round.
* @param numDecimalPlaces Optional. Default is 0.
*/
function round(num, numDecimalPlaces = 0) {
const roundedString = string.format(`%.${numDecimalPlaces}f`, num);
const roundedNum = tonumber(roundedString);
return roundedNum ?? 0;
}
/** @returns 1 if n is positive, -1 if n is negative, or 0 if n is 0. */
function sign(n) {
if (n > 0) {
return 1;
}
if (n < 0) {
return -1;
}
return 0;
}
/**
* Breaks a number into chunks of a given size. This is similar to the `String.split` method, but
* for a number instead of a string.
*
* For example, `splitNumber(90, 25)` would return an array with four elements:
*
* - [1, 25]
* - [26, 50]
* - [51, 75]
* - [76, 90]
*
* @param num The number to split into chunks. This must be a positive integer.
* @param size The size of each chunk. This must be a positive integer.
* @param startAtZero Whether to start at 0. Defaults to false. If true, the chunks will start at 0
* instead of 1.
*/
function splitNumber(num, size, startAtZero = false) {
if (num <= 0) {
error(`The number to split needs to be a positive number and is instead: ${num}`);
}
if (size <= 0) {
error(`The size to split needs to be a positive number and is instead: ${num}`);
}
const chunks = [];
let start = startAtZero ? 0 : 1;
while (start <= num) {
const end = Math.min(start + size - 1, num);
chunks.push([start, end]);
start += size;
}
return chunks;
}
function tanh(x) {
return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));
}