UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

150 lines (149 loc) 5.81 kB
"use strict"; 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)); }