feat(render): псевдо-3D, всегда видимые двери, ассеты+эффекты, русификация
- Рендер переведён в псевдо-3D: наклонная PerspectiveCamera, пол лежит плашмя, персонажи/враги — вертикальные спрайты-биллборды, стены с высотой. Починен баг: пол создавался без поворота и стоял вертикально → «вывернутая» перспектива. - Двери видны всегда: закрыты (засов) во время боя, открытый проём после зачистки. - render/assets.ts: процедурные текстуры (спрайты персонажей/врагов, пол, стены, двери, снаряд, тень) + эффекты оружия (вспышка из дула, искры, облачко гибели). - Светлее палитра — исправлено «тёмное на тёмном». - Игра переименована в «Биндим Фигняшку»; полная русификация UI (ДАЛЬНИЙ/БЛИЖНИЙ, ИГРА ОКОНЧЕНА, ПОБЕДА); клавиши-подсказки оставлены латиницей. - Ввод по event.code → WASD/Q/R работают в любой раскладке (вкл. русскую). - theme.ts урезан до реально используемых тинтов (bg/swing/flash). - docs/ASSET_BRIEF.md — бриф и промпт на полную художку; доки синхронизированы. - Ядро (src/core) не тронуто — раунд чисто render/UI. 27 тестов + типы зелёные. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+40
-15
@@ -105,26 +105,51 @@
|
||||
- **`#hud`** — 2D-канвас поверх, `HudOverlay` рисует HP, индикатор режима,
|
||||
счётчик врагов, подпись комнаты, миникарту и оверлеи Game Over/Victory.
|
||||
|
||||
### ThreeRenderer — ортокамера и «плоское 2D»
|
||||
### ThreeRenderer — псевдо-3D (наклонный вид, как в Isaac)
|
||||
|
||||
- `OrthographicCamera(0, CW, 0, CH, …)` отображает мировые координаты **один в
|
||||
один** в пиксельные (x вправо, y вниз). Поэтому вся математика ядра валидна без
|
||||
пересчётов. Слои по `z` (пол < стены < сущности < снаряды).
|
||||
- Камера переворачивает ось Y → инвертируется порядок вершин → при обычном
|
||||
отсечении задних граней плоскости были бы невидимы. Поэтому все материалы —
|
||||
**`DoubleSide`** (правильный выбор для плоских спрайтов).
|
||||
Логика остаётся 2D-сверху, но РЕНДЕР — псевдо-3D:
|
||||
|
||||
> **Исторический баг №3.** Именно из-за инверсии Y и отсечения граней мир рисовался
|
||||
> «в пустоту» (чёрный экран при работающих draw-call). Лечится `DoubleSide`.
|
||||
- **Карта координат:** игровая точка `(x, y)` кладётся на пол в 3D как `(x, 0, y)`
|
||||
— пол это плоскость `Y=0`, вверх это `+Y`, «низ» игры (`y`) идёт в глубину (`Z`).
|
||||
Поэтому вся математика и **коллизии ядра без изменений** — псевдо-3D чисто визуальный.
|
||||
- **Камера** — `PerspectiveCamera`, наклонная и фиксированная на комнату (приподнята и
|
||||
отодвинута на «юг», смотрит вниз-вперёд ≈50°). Кадрирует комнату целиком.
|
||||
- **Пол** — одна горизонтальная плоскость с бесшовной текстурой (повтор по сетке).
|
||||
⚠️ Плоскость кладём ПЛАШМЯ через `flatMesh()` (поворот −90° вокруг X). Если забыть
|
||||
поворот — пол встанет вертикально и перспектива «вывернется» (был такой баг).
|
||||
- **Стены** — вертикальные плоскости по периметру с проёмами под двери.
|
||||
- **Персонажи/враги/двери/снаряды** — ВЕРТИКАЛЬНЫЕ спрайты-биллборды (плоскости в XY,
|
||||
нормаль +Z), стоящие на полу: центр на `y = высота/2`, низ на полу. Текстуры — из
|
||||
`assets.ts` (см. ниже). Материалы — `DoubleSide` (наша камера переворачивает Y, иначе
|
||||
грани отсеклись бы) + `alphaTest` для чёткого контура спрайта.
|
||||
- **Двери всегда видимы:** рисуются из `room.doors` независимо от зачистки — закрытые
|
||||
(засов) пока `!cleared`, открытый проём после. Группа комнаты пересобирается при смене
|
||||
комнаты ИЛИ смене флага `cleared`.
|
||||
- **Тени** — отдельный плоский спрайт-«пятно» под каждой сущностью.
|
||||
|
||||
### Ассеты (render/assets.ts)
|
||||
|
||||
`Assets` строит текстуры процедурно на `<canvas>` (спрайты персонажей, пол, стены,
|
||||
двери, снаряд, эффекты, тень) и кэширует их. Это «стандартный» набор без внешних файлов.
|
||||
Заменить на свои PNG — описано в `docs/HOWTO.md` и `docs/ASSET_BRIEF.md` (бриф на полную
|
||||
графику). Ключи ассетов используются и в рендере, и в брифе.
|
||||
|
||||
### Эффекты оружия
|
||||
|
||||
Рендер сам распознаёт события по состоянию (ядро не трогаем):
|
||||
- вспышка из дула — когда `player.atkCD` «подскочил» (выстрел);
|
||||
- искра — когда у врага вырос `hitTimer` (попадание);
|
||||
- облачко-«пуф» — когда мёртвый враг исчезает из комнаты.
|
||||
Эффекты — короткоживущие аддитивные спрайты-биллборды, гаснут по таймеру.
|
||||
|
||||
### Управление ресурсами GPU (важно — иначе утечки)
|
||||
|
||||
- Общие геометрии-«единицы» (`unitPlane`, `unitCircle`) масштабируются под размер
|
||||
сущности — не плодим геометрии.
|
||||
- Тайлы комнаты пересобираются **только при смене комнаты**.
|
||||
- Меши сущностей создаются/удаляются по факту появления/исчезновения
|
||||
(mark-and-sweep в `sync*`), их персональные материалы корректно `dispose()`-ятся.
|
||||
- Общие ресурсы освобождаются один раз в `dispose()`.
|
||||
- Общие геометрии переиспользуются масштабированием — не плодим геометрии.
|
||||
- Группа комнаты (пол/стены/двери) пересобирается только при смене комнаты/`cleared`;
|
||||
персональные материалы дверей `dispose()`-ятся при пересборке.
|
||||
- Спрайты сущностей и эффекты создаются/удаляются по факту появления/исчезновения
|
||||
(mark-and-sweep), их персональные материалы корректно `dispose()`-ятся.
|
||||
- Общие материалы/геометрии и `Assets` освобождаются один раз в `dispose()`.
|
||||
|
||||
## HiDPI
|
||||
|
||||
|
||||
Reference in New Issue
Block a user