Полный рефакторинг проекта в стабильную расширяемую базу рогалика. Почему: после разнесения single-file на модули потерялся вызов генерации карты (RoomMap не генерировал комнаты) → игра падала на старте; баг скрывался тем, что Bun-бандлер не проверяет типы. Архитектура: - Логика игры (src/core/) полностью отделена от рендера: без three.js и DOM, тестируется без браузера. - Рендер мира на three.js с ортокамерой (2D-вид); HUD/миникарта — 2D-канвас поверх. - Фиксированный игровой цикл 60 Гц + интерполяция (раньше скорость зависела от частоты кадров). - Seeded-RNG, ввод через абстрактные «намерения» (InputState). Возможности: - Стартовое меню с выбором уровня (Esc → меню). - Конфигуратор уровней: LevelRules + 5 пресетов (размер карты, плотность/сила врагов, HP, фиксированный seed). - Тема внешнего вида (render/theme.ts) — задел под кастомные ассеты. Качество: - 27 юнит-тестов ядра (генерация, симметрия дверей, коллизии, спавн, правила). - Два круга adversarial-ревью; исправлено 6 реальных багов (кнокбэк сквозь стены → софт-лок; незакрываемая сокровищница; фикс-сид после рестарта; перенос ввода между забегами; нет source maps; неточности в доках). - Документация: README, docs/ARCHITECTURE.md, CLAUDE.md, docs/HOWTO.md. - dist/ исключён из гита; bun.lock зафиксирован. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
29 lines
980 B
TypeScript
29 lines
980 B
TypeScript
/** Маленькие чистые математические утилиты без состояния. */
|
|
|
|
import type { Box } from './types';
|
|
|
|
/** Евклидова дистанция между точками. */
|
|
export function dist(x1: number, y1: number, x2: number, y2: number): number {
|
|
return Math.hypot(x2 - x1, y2 - y1);
|
|
}
|
|
|
|
/** Пересекаются ли два прямоугольника (AABB). */
|
|
export function overlap(a: Box, b: Box): boolean {
|
|
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
|
|
);
|
|
}
|
|
|
|
/** Ограничить значение отрезком [min, max]. */
|
|
export function clamp(v: number, min: number, max: number): number {
|
|
return v < min ? min : v > max ? max : v;
|
|
}
|
|
|
|
/** Линейная интерполяция (для плавной отрисовки между шагами). */
|
|
export function lerp(a: number, b: number, t: number): number {
|
|
return a + (b - a) * t;
|
|
}
|