622a9fd170
Inverted tower-defense browser game — deploy enemies yourself, tower auto-kills them, pocket credits, upgrade weapons. HTML + Canvas + vanilla JS, no build step. Co-Authored-By: claude-flow <ruv@ruv.net>
60 lines
1.5 KiB
JavaScript
60 lines
1.5 KiB
JavaScript
// ═══ utils.js ═══
|
|
// ============================================================
|
|
// UTILS — shared pure helpers
|
|
// ============================================================
|
|
|
|
function distSq(ax, ay, bx, by) {
|
|
const dx = ax - bx;
|
|
const dy = ay - by;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
|
|
function normalizeAngle(angle) {
|
|
while (angle > Math.PI) angle -= Math.PI * 2;
|
|
while (angle < -Math.PI) angle += Math.PI * 2;
|
|
return angle;
|
|
}
|
|
|
|
function shortestAngleDelta(from, to) {
|
|
return normalizeAngle(to - from);
|
|
}
|
|
|
|
function stepTowardAngle(current, desired, maxStep) {
|
|
const delta = shortestAngleDelta(current, desired);
|
|
if (Math.abs(delta) <= maxStep) return normalizeAngle(desired);
|
|
return normalizeAngle(current + Math.sign(delta) * maxStep);
|
|
}
|
|
|
|
function compactLiveArray(items, isLive) {
|
|
let write = 0;
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
if (isLive(item)) items[write++] = item;
|
|
}
|
|
items.length = write;
|
|
}
|
|
|
|
function clamp(value, min, max) {
|
|
return Math.max(min, Math.min(max, value));
|
|
}
|
|
|
|
function cheapestEnemyCost() {
|
|
return ENEMY_DEFS.reduce((min, d) => Math.min(min, d.cost), Infinity);
|
|
}
|
|
|
|
function countAliveEnemies() {
|
|
let count = 0;
|
|
for (const e of G.enemies) if (e.alive) count++;
|
|
return count;
|
|
}
|
|
|
|
function getEquippedWeapons() {
|
|
return G.weapons.slice(0, G.tower.weaponSlots).filter(Boolean);
|
|
}
|
|
|
|
function findWeaponInstance(instanceId) {
|
|
for (const w of G.weapons) if (w && w.instanceId === instanceId) return w;
|
|
return null;
|
|
}
|
|
|