// --------------------------------------------------------------------------- // Shared game constants & helpers (used by both the server sim and the client) // --------------------------------------------------------------------------- export const TICK_RATE = 30; // server simulation ticks per second export const SNAP_EVERY = 2; // send a snapshot every N ticks (15 Hz) export const ARENA_RADIUS = 4200; // playable circle radius in world px export const BASE_SPEED = 178; // px per second export const BOOST_MULT = 1.95; // speed multiplier while boosting export const TURN_RATE = 4.4; // radians per second export const BOOST_TURN_RATE = 3.8; // slightly stiffer steering while boosting export const START_SCORE = 25; export const MIN_BOOST_SCORE = 18; // cannot boost below this score export const BOOST_DRAIN = 16; // score per second burned while boosting export const BOOST_DROP_INTERVAL = 0.26; // seconds between tail pellets while boosting export const PELLET_COUNT = 950; // ambient pellets kept alive in the arena export const BOT_TARGET_TOTAL = 12; // arena is kept filled to this many snakes export const RESPAWN_PROTECT_TICKS = TICK_RATE * 2; // ~2s of spawn protection // --- derived snake geometry ------------------------------------------------- export function snakeRadius(score: number): number { return 5 + Math.sqrt(Math.max(0, score)) * 0.32; } export function snakePointCount(score: number): number { return Math.min(420, Math.round(14 + Math.sqrt(Math.max(0, score)) * 2.1)); } export function snakeSpacing(score: number): number { return Math.max(5.5, snakeRadius(score) * 0.5); } // --- math helpers ------------------------------------------------------------ export function clamp(v: number, lo: number, hi: number): number { return v < lo ? lo : v > hi ? hi : v; } /** Normalize an angle to (-PI, PI]. */ export function normAngle(a: number): number { while (a > Math.PI) a -= Math.PI * 2; while (a <= -Math.PI) a += Math.PI * 2; return a; } export function dist(x1: number, y1: number, x2: number, y2: number): number { return Math.hypot(x2 - x1, y2 - y1); } // --- palettes --------------------------------------------------------------- export const SNAKE_COLORS = [ '#ff5b5b', '#ffb84d', '#ffe14d', '#7dff5b', '#4dffd2', '#4dc9ff', '#8a7dff', '#c95bff', '#ff5bd0', '#9dff4d', '#5bff9d', '#ffd24d', ]; export const PELLET_COLORS = [ '#ff6b6b', '#ffd93d', '#6bff8f', '#4dd2ff', '#c586ff', '#ff8fe1', '#8ffcff', '#ffe28f', ]; export const BOT_NAMES = [ 'Noodle', 'Viper', 'Slinky', 'Zigzag', 'Cobra', 'Python', 'Nagini', 'Basilisk', 'Wiggles', 'Turbo', 'Boa', 'Rattles', 'Medusa', 'Sidewinder', 'Anaconda', 'DangerNoodle', 'Hiss', 'Monty', ];