Демо «Типичная ночь в Мытищинском лесу» — ночной лес, свет, волны, апгрейды
Самый крупный пример игры на $: зомби-шутер в духе Vampire Survivors.
Игрок сам стреляет по ближайшему врагу, игрок только уворачивается и собирает
добычу. В темноте видно ровно столько, сколько светит фонарь.
./build/russiano2d --game demos --scene shooter_witch # сам бой
./build/russiano2d --game demos --scene witch_menu # меню-интро
| Управление | Что делает |
|---|---|
WASD / стрелки |
идти |
1 / 2 / 3 или мышь |
выбрать карту апгрейда |
F |
переключить камерный пресет вручную |
R |
заново после смерти |
Esc |
в меню демо |
1. Что показывает движок
| Слой | Чем сделан | Где смотреть |
|---|---|---|
| лес |
<tilemap> из ASCII, автотайл тропы по соседям |
buildForest() |
| деревья | спрайты с коллизиями и подсказками для акустики | buildForest() |
| свет |
<light> (мягкое свечение) + engine.light.visibility для теней от стволов |
buildLights(), drawVisibility()
|
| звук |
$.audio.zone/obstacles/damping, реверберация поляны, панорама выстрелов |
installAudio() |
| VFX | кровь, лужи, трассеры ($.fx.ribbon), молнии, ударные волны, hit-stop, тряска |
tickGore(), $.fx.*
|
| камера | пресеты кадра: «ночной лес», «кровавая луна» |
tickPresets(), $.gfx.postPreset
|
| апгрейды | пауза + три карты, выбранное меняет оружие и статы |
openUpgrade(), tickWeapons()
|
| меню и смерть | отдельные сцены witch_menu и экран проигрыша |
createMenuScene() |
2. Как это устроено
Две сцены в одном демо: witch_menu — интро-меню (кнопка «Типичная ночь в Мытищинском лесу» в лаунчере
ведёт именно сюда), shooter_witch — сам забег. Обе живут в одном файле и
делят общие данные, но мир строится заново на входе в каждую — так видно, что
$.scene меняет и музыку, и весь мир.
// земля: автотайл сам подбирает тайлы тропы по соседям
const ground = $.tilemap.fromASCII(rows, { '.': 1, ',': 2, 'p': PATH_MARK });
ground.autotile({ mode: 'terrain', terrain: 'path' });
// фонарь: свет — обычный узел, платится одним свечением на кадр
$('<light>', { radius: 235, intensity: 1, color: '#ffbe73', falloff: 2.2 })
.at(lamp.x, lamp.y).appendTo($.world);
3. Своё такое демо
-
Мир.
<tilemap>+autotileдля органичной земли, спрайты для объектов —docs/highlevel/tilemap.md. -
Свет.
<light>на фонарях; если нужны тени от препятствий —engine.light.visibility(...)и рисование полигона из$.render(демоlightбольше нет, рабочий пример остался здесь). -
Волны. Таймер + спавн за экраном:
$.time.every(ms, …)и проверка, что враг вне кадра. -
Прогресс. Кристаллы как
<pickup>, уровень — свой счётчик, карты апгрейдов — пауза$.time.pause()и три кнопки. -
Проверка без рук.
python3 tests/agent/demos_test.py shooter_witch— тест гоняет 900 кадров боя и требует, чтобы враги гибли и в журнале не было ошибок игрового кода.
4. Производительность
Демо сознательно тяжёлое: тысячи тайлов, десятки врагов, кровь и частицы.
Ориентиры, на которые смотрели при написании: список узлов мира
переиспользуется, свет — узлы <light> вместо ручных полигонов на каждого
врага, кровь — пул объектов ($.pool). Если своё демо тормозит, начните с
$.debug.profiler.on(true) и F1 — разбор в
docs/HIGH_LEVEL_API_PERF.md.
5. Ассеты
Лес — CC0 Kenney RPG/Urban, персонаж — лист из demos/assets/art/characters,
музыка и звуки — CC0 Juhani Junkala. Полный список с лицензиями:
demos/assets/CREDITS.md.