138 lines
3.6 KiB
JavaScript
138 lines
3.6 KiB
JavaScript
/**
|
||
* 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 });
|
||
}
|