// 通用工具 export const TILE = 32; export const ROOM_W = 800; export const ROOM_H = 608; export const GRID_W = ROOM_W / TILE; // 25 export const GRID_H = ROOM_H / TILE; // 19 export const clamp = (v, a, b) => (v < a ? a : v > b ? b : v); export const lerp = (a, b, t) => a + (b - a) * t; export const sgn = v => (v < 0 ? -1 : v > 0 ? 1 : 0); export const rand = (a, b) => a + Math.random() * (b - a); export const randInt = (a, b) => Math.floor(a + Math.random() * (b - a + 1)); export const pick = arr => arr[Math.floor(Math.random() * arr.length)]; export function overlap(a, b) { return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y; } export function pointIn(px, py, r) { return px >= r.x && px <= r.x + r.w && py >= r.y && py <= r.y + r.h; } /** 浅色/深色化 hex 颜色,n>0 变亮 n<0 变暗 */ export function shade(hex, n) { const h = hex.replace('#', ''); const v = parseInt(h.length === 3 ? h.split('').map(c => c + c).join('') : h, 16); let r = (v >> 16) & 255, g = (v >> 8) & 255, b = v & 255; r = clamp(r + n, 0, 255); g = clamp(g + n, 0, 255); b = clamp(b + n, 0, 255); return `rgb(${r},${g},${b})`; } /** 时间毫秒 -> m:ss.cc */ export function fmtTime(ms) { const t = Math.max(0, ms); const m = Math.floor(t / 60000); const s = Math.floor((t % 60000) / 1000); const c = Math.floor((t % 1000) / 10); return `${m}:${String(s).padStart(2, '0')}.${String(c).padStart(2, '0')}`; } /** 平滑的确定性伪随机(用于装饰,不影响帧同步) */ export function hashNoise(x, y) { let h = x * 374761393 + y * 668265263; h = (h ^ (h >> 13)) * 1274126177; return ((h ^ (h >> 16)) >>> 0) / 4294967295; }