Files
slop-game-opus5.5/app/static/js/logic/math.js
T
2026-09-24 17:57:54 +02:00

138 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Kleine Vektor- und Zahlenhelfer ohne Phaser-Abhängigkeit.
* Vektoren sind einfache Objekte `{x, y}`; die Funktionen verändern ihre Eingaben nie.
* @module logic/math
*/
/** @typedef {{x: number, y: number}} Vec2 */
/**
* Begrenzt `value` auf das Intervall [min, max].
* @param {number} value
* @param {number} min
* @param {number} max
* @returns {number}
*/
export function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
/**
* Lineare Interpolation zwischen `a` und `b`.
* @param {number} a
* @param {number} b
* @param {number} t 0..1
* @returns {number}
*/
export function lerp(a, b, t) {
return a + (b - a) * t;
}
/** @param {number} deg @returns {number} */
export function degToRad(deg) {
return (deg * Math.PI) / 180;
}
/** @param {number} x @param {number} y @returns {Vec2} */
export function vec(x = 0, y = 0) {
return { x, y };
}
/** @param {Vec2} a @param {Vec2} b @returns {Vec2} */
export function add(a, b) {
return { x: a.x + b.x, y: a.y + b.y };
}
/** @param {Vec2} a @param {Vec2} b @returns {Vec2} */
export function sub(a, b) {
return { x: a.x - b.x, y: a.y - b.y };
}
/** @param {Vec2} v @param {number} s @returns {Vec2} */
export function scale(v, s) {
return { x: v.x * s, y: v.y * s };
}
/** @param {Vec2} v @returns {number} */
export function length(v) {
return Math.hypot(v.x, v.y);
}
/** @param {Vec2} a @param {Vec2} b @returns {number} */
export function distance(a, b) {
return Math.hypot(b.x - a.x, b.y - a.y);
}
/**
* Einheitsvektor in Richtung `v`. Der Nullvektor bleibt der Nullvektor –
* so muss kein Aufrufer Division durch null abfangen.
* @param {Vec2} v
* @returns {Vec2}
*/
export function normalize(v) {
const len = length(v);
return len > 0 ? { x: v.x / len, y: v.y / len } : { x: 0, y: 0 };
}
/**
* Kürzt `v` auf höchstens `max` Länge, die Richtung bleibt erhalten.
* @param {Vec2} v
* @param {number} max
* @returns {Vec2}
*/
export function clampLength(v, max) {
const len = length(v);
return len > max && len > 0 ? scale(v, max / len) : { x: v.x, y: v.y };
}
/**
* Dreht `v` um `angle` (Bogenmaß, im Uhrzeigersinn bei y nach unten wie im Canvas).
* @param {Vec2} v
* @param {number} angle
* @returns {Vec2}
*/
export function rotate(v, angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return { x: v.x * cos - v.y * sin, y: v.x * sin + v.y * cos };
}
/**
* Winkel des Vektors von `from` nach `to` (Bogenmaß, 0 = nach rechts).
* @param {Vec2} from
* @param {Vec2} to
* @returns {number}
*/
export function angleTo(from, to) {
return Math.atan2(to.y - from.y, to.x - from.x);
}
/** @param {number} angle @returns {Vec2} Einheitsvektor für den Winkel. */
export function fromAngle(angle) {
return { x: Math.cos(angle), y: Math.sin(angle) };
}
/**
* Prüft, ob ein Punkt in einem Kreis liegt (inkl. Radius eines Objekts).
* @param {Vec2} point
* @param {Vec2} center
* @param {number} radius
* @param {number} [objectRadius=0] Ausdehnung des Objekts, damit große Gegner am Rand zählen.
* @returns {boolean}
*/
export function inCircle(point, center, radius, objectRadius = 0) {
return distance(point, center) <= radius + objectRadius;
}
/**
* Richtungsvektor aus gedrückten Tasten; diagonal wird normalisiert, damit man
* schräg nicht schneller läuft (klassischer 8-Wege-Fehler).
* @param {{up: boolean, down: boolean, left: boolean, right: boolean}} keys
* @returns {Vec2}
*/
export function directionFromKeys(keys) {
const x = (keys.right ? 1 : 0) - (keys.left ? 1 : 0);
const y = (keys.down ? 1 : 0) - (keys.up ? 1 : 0);
return normalize({ x, y });
}