Race 2: своя палитра и небо, чистовое запекание, вентиляторы сильнее, скрытая шахта, новая песня
- палитра целиком (индиго, пурпур, ледяная бирюза): SOLID/NEON, SURFACES/GLOWS, туман, ambient, свет запекания, ворота, полосы, надписи; новое небо - запекание 384 сэмпла + огни у подножия башни - вентилятор: VENT_MAX_RISE 16, VENT_ACCEL 80; шахта-лифт без знака и без столба/света (hidden) - музыка Race 2: Poloz «On My Way to Hell» с 1:40 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -135,7 +135,7 @@ tools/ export_all.sh, serve_web.py, deploy_server.sh, test/ (
|
|||||||
| Backrooms | `maps/backrooms/backrooms.tscn` | `backrooms.pck` | Модель «Backrooms VR» (×1,4). Преследователь: **Верити** (масштаб 0,5). Выход «EXIT» в дальнем конце ведёт в хаб. Гул ламп генерируется кодом |
|
| Backrooms | `maps/backrooms/backrooms.tscn` | `backrooms.pck` | Модель «Backrooms VR» (×1,4). Преследователь: **Верити** (масштаб 0,5). Выход «EXIT» в дальнем конце ведёт в хаб. Гул ламп генерируется кодом |
|
||||||
| Parkour | `maps/parkour/parkour.tscn` | `parkour.pck` (7,4 МБ: небо 3,5 + модель 3,4 + музыка 1,1) | Мрачная антиутопия в духе Ghostrunner: дождь, дымный воздух, грязный мокрый бетон, натриевый оранжевый, тревожный красный и больной зелёный свет, надписи-приказы (COMPLY, CURFEW 22:00, RESTRICTED). **Забег на время** (старт — линия на краю стартовой платформы, финиш — вершина; рейтинг на сервере; R — заново). Подъём по мегабашне, ~700 м, 9 чекпоинтов (светящиеся ворота), без преследователей. Секции: крыши (одинарный/двойной прыжок, подтягивание) → каньон из четырёх стен для бега → башня из 9 уступов (двойной прыжок + подтягивание) → лазерный зал (подкат, прыжок, тайминг, рывок) → пропасть из 6 контейнеров (зазоры 16–24 м) → спираль вокруг светящегося ядра (+24 м) → вершина с порталом в хаб. Срыв ниже последнего чекпоинта на 32 м или касание лазера = «СОРВАЛСЯ!» и возрождение на чекпоинте. Музыка: `maps/parkour/audio/music.ogg` (Ogg Vorbis, моно 32 кГц, ~1 МБ; делается `ffmpeg -i исходник.mp3 -ac 1 -ar 32000 -c:a libvorbis -q:a 0 music.ogg`), играет по кругу |
|
| Parkour | `maps/parkour/parkour.tscn` | `parkour.pck` (7,4 МБ: небо 3,5 + модель 3,4 + музыка 1,1) | Мрачная антиутопия в духе Ghostrunner: дождь, дымный воздух, грязный мокрый бетон, натриевый оранжевый, тревожный красный и больной зелёный свет, надписи-приказы (COMPLY, CURFEW 22:00, RESTRICTED). **Забег на время** (старт — линия на краю стартовой платформы, финиш — вершина; рейтинг на сервере; R — заново). Подъём по мегабашне, ~700 м, 9 чекпоинтов (светящиеся ворота), без преследователей. Секции: крыши (одинарный/двойной прыжок, подтягивание) → каньон из четырёх стен для бега → башня из 9 уступов (двойной прыжок + подтягивание) → лазерный зал (подкат, прыжок, тайминг, рывок) → пропасть из 6 контейнеров (зазоры 16–24 м) → спираль вокруг светящегося ядра (+24 м) → вершина с порталом в хаб. Срыв ниже последнего чекпоинта на 32 м или касание лазера = «СОРВАЛСЯ!» и возрождение на чекпоинте. Музыка: `maps/parkour/audio/music.ogg` (Ogg Vorbis, моно 32 кГц, ~1 МБ; делается `ffmpeg -i исходник.mp3 -ac 1 -ar 32000 -c:a libvorbis -q:a 0 music.ogg`), играет по кругу |
|
||||||
| Race | `maps/race/race.tscn` | `race.pck` | Гонка на ногах до 8 игроков (кто быстрее до финиша), мрачный город: стартовая площадка → рынок → эстакада → крыши → каньон → ангар. 8 ворот-чекпоинтов, 2 лазера, развилки с обходами. Правила и сеть — раздел «Карта Race» ниже |
|
| Race | `maps/race/race.tscn` | `race.pck` | Гонка на ногах до 8 игроков (кто быстрее до финиша), мрачный город: стартовая площадка → рынок → эстакада → крыши → каньон → ангар. 8 ворот-чекпоинтов, 2 лазера, развилки с обходами. Правила и сеть — раздел «Карта Race» ниже |
|
||||||
| Race 2 | `maps/race2/race2.tscn` | `race2.pck` (8,8 МБ) | «Верхние ярусы»: гонка по крышам и мостам над городом, 13 ворот, ~1,2 км безопасного пути; на каждом участке безопасный / рискованный / секретный путь; вентиляторы-подбросы и ускоряющие полосы. Правила те же, что у Race (общий код). Раздел «Карта Race 2» |
|
| Race 2 | `maps/race2/race2.tscn` | `race2.pck` (9,5 МБ) | «Верхние ярусы»: гонка по крышам и мостам над городом, 13 ворот, ~1,2 км безопасного пути; на каждом участке безопасный / рискованный / секретный путь; вентиляторы-подбросы и ускоряющие полосы. Правила те же, что у Race (общий код). Раздел «Карта Race 2» |
|
||||||
|
|
||||||
**Правка и пересборка Parkour** (всё в `Blender models/parkour_02/`):
|
**Правка и пересборка Parkour** (всё в `Blender models/parkour_02/`):
|
||||||
1. `layout.py` — единственный источник: плиты, стены, лазеры, чекпоинты и расчёт зазоров под мувсет (замеры ботом: прыжок на спринте 15 м, двойной 25 м, прыжок+рывок 19 м, двойной+рывок 28 м, бег по стене 1,8 с / 23 м, подтягивание на уступ до ~2,6 м; **стенами высоту не набрать** — прыжков от стены без бега только 2 за полёт).
|
1. `layout.py` — единственный источник: плиты, стены, лазеры, чекпоинты и расчёт зазоров под мувсет (замеры ботом: прыжок на спринте 15 м, двойной 25 м, прыжок+рывок 19 м, двойной+рывок 28 м, бег по стене 1,8 с / 23 м, подтягивание на уступ до ~2,6 м; **стенами высоту не набрать** — прыжков от стены без бега только 2 за полёт).
|
||||||
@@ -197,17 +197,17 @@ tools/ export_all.sh, serve_web.py, deploy_server.sh, test/ (
|
|||||||
|
|
||||||
## Карта Race 2 («Верхние ярусы»)
|
## Карта Race 2 («Верхние ярусы»)
|
||||||
|
|
||||||
**Состояние: фаза 1** (раскладка, геометрия, ворота, правила, проходимость ботами, предварительный свет). **Фаза 2** — после одобрения владельцем: чистовое запекание (384+ сэмплов), своё небо (`build_sky.py`), своя музыка. Пока небо и песня — копии Race.
|
**Состояние: фаза 1** (раскладка, геометрия, ворота, правила, проходимость ботами, предварительный свет). **Фаза 2** — после одобрения владельцем: чистовое запекание (384+ сэмплов), своё небо (`build_sky.py`), своя музыка. Палитра своя (холодная индиго-ночь, пурпур и ледяная бирюза; ворота тусклые индиго / очередные маджента / пройденные циан), небо перерисовано (`build_sky.py`), свет запечён на 384 сэмплах. Музыка — «On My Way to Hell» (Poloz), с 1:40 исходника (`ffmpeg -ss 100 -i исходник.mp3 -vn -map_metadata -1 -ac 1 -ar 32000 -c:a libvorbis -q:a 0 maps/race2/audio/music.ogg`, ~3:40, 1,2 МБ; исходник вне проекта: `source-assets/music/`); играет с «СТАРТ!» с начала по кругу (`loop = true`, затухание 0,8 с). Стык петли на слух/по уровню не проверен.
|
||||||
Исходники: `Blender models/race_02/` (README там же; репозитория у папки нет — файлы не коммитятся). Концепция согласована с владельцем: вертикальность и поток скорости в духе Ghostrunner, но атмосфера как у Race/Parkour (дождь, смог, мокрый бетон, натриевый/красный/больной зелёный свет, надписи-приказы), туман 0,011.
|
Исходники: `Blender models/race_02/` (README там же; репозитория у папки нет — файлы не коммитятся). Концепция согласована с владельцем: вертикальность и поток скорости в духе Ghostrunner, но атмосфера как у Race/Parkour (дождь, смог, мокрый бетон, натриевый/красный/больной зелёный свет, надписи-приказы), туман 0,011.
|
||||||
|
|
||||||
Файлы: `maps/race2/` — `race2.tscn`, `race2.gd` (внешний вид, ворота со световыми столбами, лазеры, вентиляторы, полосы, срыв, дождь без дождя в траншее и шахте, гул, портал), `race2_data.gd` (**генерируется** `build_race.py`, не править),
|
Файлы: `maps/race2/` — `race2.tscn`, `race2.gd` (внешний вид, ворота со световыми столбами, лазеры, вентиляторы, полосы, срыв, дождь без дождя в траншее и шахте, гул, портал), `race2_data.gd` (**генерируется** `build_race.py`, не править),
|
||||||
`race2.glb`, `sky.png`, `baked.gdshader`, `audio/music.ogg`. **Правила — общие с Race:** `race2.gd` создаёт тот же `maps/race/race_rules.gd` и передаёт ему `data` (= `race2_data.gd`) и `rating_id` (= `"race2"`); `race_rules.gd` берёт данные у карты
|
`race2.glb`, `sky.png`, `baked.gdshader`, `audio/music.ogg`. **Правила — общие с Race:** `race2.gd` создаёт тот же `maps/race/race_rules.gd` и передаёт ему `data` (= `race2_data.gd`) и `rating_id` (= `"race2"`); `race_rules.gd` берёт данные у карты
|
||||||
(`m.get("data")`, у Race — запасной `load` его `race_data.gd`). Пакет `race2.pck` (8,8 МБ) собирается пресетом **Race2** (в нём `include_filter`: `maps/race/race_rules.gd` и файлы карты); скрипты `objects/vent.gd` и `objects/boost_strip.gd` — в **основном** пакете.
|
(`m.get("data")`, у Race — запасной `load` его `race_data.gd`). Пакет `race2.pck` (9,5 МБ) собирается пресетом **Race2** (в нём `include_filter`: `maps/race/race_rules.gd` и файлы карты); скрипты `objects/vent.gd` и `objects/boost_strip.gd` — в **основном** пакете.
|
||||||
Рейтинг: `Net.TIMED_MAPS["race2"] = {"min": 44}` (≈ 60 % от лучшего круга ботом по всем секретам ~72 с), `Net.MAP_TITLES["race2"] = "Гонка 2"`; в хабе портал «RACE 2» пятым в ряду.
|
Рейтинг: `Net.TIMED_MAPS["race2"] = {"min": 44}` (≈ 60 % от лучшего круга ботом по всем секретам ~72 с), `Net.MAP_TITLES["race2"] = "Гонка 2"`; в хабе портал «RACE 2» пятым в ряду.
|
||||||
|
|
||||||
**Новые объекты** (локальный эффект на игроке, сетевой код не тронут; в `player/player.gd` — только хуки `apply_vent()` и `apply_boost()` и константы `VENT_ACCEL`, `VENT_MAX_RISE`, `BOOST_ACCEL`, `EFFECT_HOLD`; остальная физика и `MAX_SPEED = 22` не менялись):
|
**Новые объекты** (локальный эффект на игроке, сетевой код не тронут; в `player/player.gd` — только хуки `apply_vent()` и `apply_boost()` и константы `VENT_ACCEL`, `VENT_MAX_RISE`, `BOOST_ACCEL`, `EFFECT_HOLD`; остальная физика и `MAX_SPEED = 22` не менялись):
|
||||||
- **Вентиляционный поток** (`objects/vent.gd`): пока игрок в столбе, вертикальная скорость растёт до 11 м/с (ускорение 60 м/с²), горизонтальная сохраняется, двойной прыжок возвращается. Столб шириной 6 м даёт подъём около 12 м на ступень (ступени башни — 12,5 м, с двойным прыжком). Визуал: тёмная решётка со светящимися щелями, мерцающий зелёный столб, слабый свет.
|
- **Вентиляционный поток** (`objects/vent.gd`): пока игрок в столбе, вертикальная скорость растёт до **16 м/с** (ускорение 80 м/с²; раньше 11 и 60), горизонтальная сохраняется, двойной прыжок возвращается. Выход из столба на 16 м/с даёт ещё ~13 м высоты (v²/2g), поэтому ступень башни 12,5 м берётся с перелётом ~3 м; ступени 14–15 м в пробах ботом вели к промахам и оставлены 12,5. Шахта-лифт — скрытый поток (`hidden`: без столба, щелей и света), над окном знака нет. Визуал: тёмная решётка со светящимися щелями, мерцающий зелёный столб, слабый свет.
|
||||||
- **Ускоряющая полоса** (`objects/boost_strip.gd`): набор скорости вдоль полосы до 22 м/с (не выше `MAX_SPEED`), потом на земле она гасится как обычно (14 м/с²), в воздухе сохраняется. Измерено: на 22 м/с одиночный прыжок 25 м, двойной 42 м; **рывок сбрасывает скорость до 13**. Стрелки бирюзовые, бегут по ходу (жёлтые статичные — подсказки трассы).
|
- **Ускоряющая полоса** (`objects/boost_strip.gd`): набор скорости вдоль полосы до 22 м/с (не выше `MAX_SPEED`), потом на земле она гасится как обычно (14 м/с²), в воздухе сохраняется. Измерено: на 22 м/с одиночный прыжок 25 м, двойной 42 м; **рывок сбрасывает скорость до 13**. Стрелки пурпурно-белые, бегут по ходу (статичные ледяные — подсказки трассы).
|
||||||
|
|
||||||
**Участки и три пути** (подробности и координаты — `Blender models/race_02/README.md`, `layout.py`): старт на верхней платформе (8 слотов, шаг 2,8 м) → 2) мосты и крыши между башнями → 3) фасады: бег по четырём стенам → 4) площадь с краном → 5) пульсирующие лазерные мосты → 6) спуск по крышам → 7) башня-спираль из четырёх вентиляторов; на крыше ядра — финиш и портал.
|
**Участки и три пути** (подробности и координаты — `Blender models/race_02/README.md`, `layout.py`): старт на верхней платформе (8 слотов, шаг 2,8 м) → 2) мосты и крыши между башнями → 3) фасады: бег по четырём стенам → 4) площадь с краном → 5) пульсирующие лазерные мосты → 6) спуск по крышам → 7) башня-спираль из четырёх вентиляторов; на крыше ядра — финиш и портал.
|
||||||
Безопасный путь 1085 м до подножия башни + 136 м башня = **1221 м** (план ~1100; можно сжать зоны 4 и 6), 13 ворот (ширина до 100 м там, где ветки расходятся широко), круг бота по безопасному пути ~99 с.
|
Безопасный путь 1085 м до подножия башни + 136 м башня = **1221 м** (план ~1100; можно сжать зоны 4 и 6), 13 ворот (ширина до 100 м там, где ветки расходятся широко), круг бота по безопасному пути ~99 с.
|
||||||
@@ -228,7 +228,7 @@ tools/ export_all.sh, serve_web.py, deploy_server.sh, test/ (
|
|||||||
Итого все секреты вместе экономят ~26 с из ~99 (оценка бота; человек на секретах рискует сорваться на последние ворота). **Правила на race2:** `MAP=race2 tools/test/race_game_test.sh` (бот проводит игроков через ворота телепортами по 0,35 м за кадр, на лазерном мосту выбирает полосу — проверяются отсчёт, места, итоги, один START, возрождение лицом по трассе, зритель; проходимость проверена отдельно). Рейтинг этим тестом не проверяется: круг бота ~60 с — запись возможна, но тест рейтинг не сверяет.
|
Итого все секреты вместе экономят ~26 с из ~99 (оценка бота; человек на секретах рискует сорваться на последние ворота). **Правила на race2:** `MAP=race2 tools/test/race_game_test.sh` (бот проводит игроков через ворота телепортами по 0,35 м за кадр, на лазерном мосту выбирает полосу — проверяются отсчёт, места, итоги, один START, возрождение лицом по трассе, зритель; проходимость проверена отдельно). Рейтинг этим тестом не проверяется: круг бота ~60 с — запись возможна, но тест рейтинг не сверяет.
|
||||||
Пакет: `godot --headless --export-pack Race2 /tmp/x/race2.pck`, затем `strings` по `sky.png`, `baked.gdshader`, `race2_data`, `race_rules.gd`, `music.ogg`, `race2.glb`, `race2.gd` (каждое > 0; vent/boost_strip в этом пакете нет — они в основном). Через портал хаба: `tools/test/race2_check.txt`.
|
Пакет: `godot --headless --export-pack Race2 /tmp/x/race2.pck`, затем `strings` по `sky.png`, `baked.gdshader`, `race2_data`, `race_rules.gd`, `music.ogg`, `race2.glb`, `race2.gd` (каждое > 0; vent/boost_strip в этом пакете нет — они в основном). Через портал хаба: `tools/test/race2_check.txt`.
|
||||||
|
|
||||||
**Что не сделано / известно:** свет запечён грубо (пятна), небо и музыка от Race; `race2.glb` 8,4 МБ против 5,2 у Race (в фазе 2 прореживать фон); у зон 1 и 7 нет рискованной ветки; зазор для безопасного пути на спуске к `lane` — 8 м при спуске 9,2 м; не мерялись: нагрузка в браузере и звук. **Выкладка:** `net/net.gd` изменён только константами (`TIMED_MAPS`, `MAP_TITLES`), RPC те же — но сервер без нового `net.gd` **не примет рекорды race2** (запись отклонит: карты нет в `TIMED_MAPS`), поэтому после пуша `grid-world` запустить `tools/deploy_server.sh`; порядок и бэкап — как в «Деплой».
|
**Что не сделано / известно:** после смены силы вентиляторов (11 -> 16 м/с) проходимость башни и траншеи проверена ботом только выборочно (cmp7_safe, secret7, cmp4_secret, risky4 прошли), полный прогон и таблица времён выше — до этой правки, не перемерены; подножие башни всё ещё тёмное; `race2.glb` 8,4 МБ против 5,2 у Race (в фазе 2 прореживать фон); у зон 1 и 7 нет рискованной ветки; зазор для безопасного пути на спуске к `lane` — 8 м при спуске 9,2 м; не мерялись: нагрузка в браузере и звук. **Выкладка:** `net/net.gd` изменён только константами (`TIMED_MAPS`, `MAP_TITLES`), RPC те же — но сервер без нового `net.gd` **не примет рекорды race2** (запись отклонит: карты нет в `TIMED_MAPS`), поэтому после пуша `grid-world` запустить `tools/deploy_server.sh`; порядок и бэкап — как в «Деплой».
|
||||||
|
|
||||||
## Ники и рейтинг
|
## Ники и рейтинг
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
+17
-16
@@ -48,16 +48,16 @@ func _ready() -> void:
|
|||||||
|
|
||||||
# Цвета поверхностей — те же значения, что в Blender (kit.py: SOLID); освещение уже запечено в цветах вершин
|
# Цвета поверхностей — те же значения, что в Blender (kit.py: SOLID); освещение уже запечено в цветах вершин
|
||||||
const SURFACES := {
|
const SURFACES := {
|
||||||
"Concrete": Color(0.11, 0.115, 0.125), "Dark": Color(0.016, 0.017, 0.02), "Steel": Color(0.13, 0.14, 0.15),
|
"Concrete": Color(0.095, 0.105, 0.15), "Dark": Color(0.012, 0.013, 0.024), "Steel": Color(0.115, 0.125, 0.185),
|
||||||
"PaintY": Color(0.38, 0.30, 0.06), "PaintR": Color(0.26, 0.08, 0.05), "PaintB": Color(0.05, 0.08, 0.11),
|
"PaintY": Color(0.30, 0.10, 0.36), "PaintR": Color(0.22, 0.05, 0.16), "PaintB": Color(0.04, 0.06, 0.18),
|
||||||
"PaintO": Color(0.33, 0.14, 0.05),
|
"PaintO": Color(0.14, 0.09, 0.30),
|
||||||
}
|
}
|
||||||
# Светящиеся (мрачная палитра): Cyan — холодный белёсый, Magenta — тревожный красный, Orange — натриевая лампа
|
# Светящиеся (мрачная палитра): Cyan — холодный белёсый, Magenta — тревожный красный, Orange — натриевая лампа
|
||||||
const GLOWS := {
|
const GLOWS := {
|
||||||
"NeonCyan": [Color(0.50, 0.86, 0.82), 0.65], "NeonMagenta": [Color(0.95, 0.07, 0.04), 1.2],
|
"NeonCyan": [Color(0.30, 0.85, 0.98), 0.7], "NeonMagenta": [Color(0.85, 0.08, 0.65), 1.2],
|
||||||
"NeonOrange": [Color(1.0, 0.42, 0.08), 1.3], "NeonYellow": [Color(0.92, 0.62, 0.10), 1.1],
|
"NeonOrange": [Color(0.55, 0.22, 1.0), 1.3], "NeonYellow": [Color(0.72, 0.84, 1.0), 1.0],
|
||||||
"NeonGreen": [Color(0.45, 0.85, 0.35), 1.0], "NeonBlue": [Color(0.25, 0.40, 0.70), 1.0],
|
"NeonGreen": [Color(0.25, 0.95, 0.75), 1.0], "NeonBlue": [Color(0.28, 0.32, 0.92), 1.0],
|
||||||
"NeonRed": [Color(1.0, 0.05, 0.05), 1.5], "NeonWhite": [Color(1.0, 0.72, 0.42), 0.9],
|
"NeonRed": [Color(1.0, 0.06, 0.28), 1.5], "NeonWhite": [Color(0.72, 0.82, 1.0), 0.9],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Коллизию создаёт импорт (узел Collision-colonly), здесь — внешний вид: материалы по именам из Blender
|
# Коллизию создаёт импорт (узел Collision-colonly), здесь — внешний вид: материалы по именам из Blender
|
||||||
@@ -120,10 +120,10 @@ func _build_environment() -> void:
|
|||||||
env.background_mode = Environment.BG_SKY
|
env.background_mode = Environment.BG_SKY
|
||||||
env.sky = sky
|
env.sky = sky
|
||||||
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR # свет на самом игроке/призраках; уровень освещён запечённо
|
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR # свет на самом игроке/призраках; уровень освещён запечённо
|
||||||
env.ambient_light_color = Color(0.26, 0.29, 0.33)
|
env.ambient_light_color = Color(0.20, 0.22, 0.40)
|
||||||
env.ambient_light_energy = 0.6
|
env.ambient_light_energy = 0.6
|
||||||
env.fog_enabled = true
|
env.fog_enabled = true
|
||||||
env.fog_light_color = Color(0.2, 0.16, 0.13) # грязный дымный воздух
|
env.fog_light_color = Color(0.10, 0.09, 0.24) # холодный индиго-дым высоких ярусов
|
||||||
env.fog_density = 0.011
|
env.fog_density = 0.011
|
||||||
env.fog_sky_affect = 0.45
|
env.fog_sky_affect = 0.45
|
||||||
env.tonemap_mode = Environment.TONE_MAPPER_FILMIC
|
env.tonemap_mode = Environment.TONE_MAPPER_FILMIC
|
||||||
@@ -133,13 +133,13 @@ func _build_environment() -> void:
|
|||||||
env.glow_hdr_threshold = 1.0
|
env.glow_hdr_threshold = 1.0
|
||||||
env.adjustment_enabled = true
|
env.adjustment_enabled = true
|
||||||
env.adjustment_contrast = 1.15
|
env.adjustment_contrast = 1.15
|
||||||
env.adjustment_saturation = 0.8
|
env.adjustment_saturation = 0.9
|
||||||
var we := WorldEnvironment.new()
|
var we := WorldEnvironment.new()
|
||||||
we.environment = env
|
we.environment = env
|
||||||
add_child(we)
|
add_child(we)
|
||||||
var sun := DirectionalLight3D.new() # подсветка только для персонажей
|
var sun := DirectionalLight3D.new() # подсветка только для персонажей
|
||||||
sun.rotation_degrees = Vector3(-55.0, 35.0, 0.0)
|
sun.rotation_degrees = Vector3(-55.0, 35.0, 0.0)
|
||||||
sun.light_color = Color(0.6, 0.68, 0.75)
|
sun.light_color = Color(0.5, 0.58, 0.95)
|
||||||
sun.light_energy = 0.4
|
sun.light_energy = 0.4
|
||||||
add_child(sun)
|
add_child(sun)
|
||||||
|
|
||||||
@@ -156,9 +156,9 @@ func _emissive(color: Color, energy: float, alpha := 1.0) -> StandardMaterial3D:
|
|||||||
|
|
||||||
# ---------- ворота: высокие светящиеся рамы поперёк трассы ----------
|
# ---------- ворота: высокие светящиеся рамы поперёк трассы ----------
|
||||||
|
|
||||||
const GATE_OFF := Color(0.55, 0.30, 0.14) # ещё не очередные: тусклые
|
const GATE_OFF := Color(0.30, 0.26, 0.55) # ещё не очередные: тусклый индиго
|
||||||
const GATE_NEXT := Color(1.0, 0.5, 0.15) # очередные: яркий натриевый
|
const GATE_NEXT := Color(1.0, 0.18, 0.85) # очередные: яркая маджента
|
||||||
const GATE_DONE := Color(0.45, 0.85, 0.35) # пройдены: зелёные
|
const GATE_DONE := Color(0.25, 0.95, 0.95) # пройдены: ледяной циан
|
||||||
|
|
||||||
# Угол рыскания из данных (0 = вдоль -Z, -90 = на +X) — это ровно rotation.y в Godot
|
# Угол рыскания из данных (0 = вдоль -Z, -90 = на +X) — это ровно rotation.y в Godot
|
||||||
func gate_yaw(i: int) -> float:
|
func gate_yaw(i: int) -> float:
|
||||||
@@ -241,7 +241,7 @@ func _add_laser(d: Array) -> void:
|
|||||||
area.add_child(cs)
|
area.add_child(cs)
|
||||||
var bm := BoxMesh.new()
|
var bm := BoxMesh.new()
|
||||||
bm.size = d[1]
|
bm.size = d[1]
|
||||||
var mat := _emissive(Color(1.0, 0.04, 0.05), 2.4, 0.35 if d[1].y > 3.0 else 1.0)
|
var mat := _emissive(Color(1.0, 0.05, 0.22), 2.4, 0.35 if d[1].y > 3.0 else 1.0)
|
||||||
var mesh := _part(bm, mat, Vector3.ZERO)
|
var mesh := _part(bm, mat, Vector3.ZERO)
|
||||||
area.add_child(mesh)
|
area.add_child(mesh)
|
||||||
add_child(area)
|
add_child(area)
|
||||||
@@ -266,6 +266,7 @@ func _add_vent(d: Array) -> void:
|
|||||||
a.set_script(load("res://objects/vent.gd"))
|
a.set_script(load("res://objects/vent.gd"))
|
||||||
a.size = d[1]
|
a.size = d[1]
|
||||||
a.height = d[2]
|
a.height = d[2]
|
||||||
|
a.hidden = d[3]
|
||||||
a.position = d[0]
|
a.position = d[0]
|
||||||
add_child(a)
|
add_child(a)
|
||||||
|
|
||||||
@@ -315,7 +316,7 @@ func _add_rain() -> void:
|
|||||||
var mat := StandardMaterial3D.new()
|
var mat := StandardMaterial3D.new()
|
||||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
mat.albedo_color = Color(0.7, 0.78, 0.82, 0.3)
|
mat.albedo_color = Color(0.62, 0.7, 0.95, 0.3)
|
||||||
mat.billboard_mode = BaseMaterial3D.BILLBOARD_FIXED_Y
|
mat.billboard_mode = BaseMaterial3D.BILLBOARD_FIXED_Y
|
||||||
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
quad.material = mat
|
quad.material = mat
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ const LASERS := [
|
|||||||
[Vector3(112.00, 52.25, -608.25), Vector3(4.00, 0.90, 0.50), 1, 3.00, 1.00, 1.50], # mR4
|
[Vector3(112.00, 52.25, -608.25), Vector3(4.00, 0.90, 0.50), 1, 3.00, 1.00, 1.50], # mR4
|
||||||
]
|
]
|
||||||
|
|
||||||
# Вентиляционные потоки: центр решётки на полу, сечение (X, Z), высота столба
|
# Вентиляционные потоки: центр решётки на полу, сечение (X, Z), высота столба, скрытый (без света и столба — шахта-лифт)
|
||||||
const VENTS := [
|
const VENTS := [
|
||||||
[Vector3(107.00, 43.80, -450.00), Vector2(6.00, 6.00), 14.00], # v_tn
|
[Vector3(107.00, 43.80, -450.00), Vector2(6.00, 6.00), 14.00, false], # v_tn
|
||||||
[Vector3(230.00, 23.80, -505.00), Vector2(6.00, 6.00), 15.00], # v1
|
[Vector3(230.00, 23.80, -505.00), Vector2(6.00, 6.00), 15.00, false], # v1
|
||||||
[Vector3(230.00, 36.30, -477.00), Vector2(6.00, 6.00), 15.00], # v2
|
[Vector3(230.00, 36.30, -477.00), Vector2(6.00, 6.00), 15.00, false], # v2
|
||||||
[Vector3(198.00, 48.80, -465.00), Vector2(6.00, 6.00), 15.00], # v3
|
[Vector3(198.00, 48.80, -465.00), Vector2(6.00, 6.00), 15.00, false], # v3
|
||||||
[Vector3(190.00, 61.30, -481.00), Vector2(6.00, 6.00), 15.00], # v4
|
[Vector3(190.00, 61.30, -481.00), Vector2(6.00, 6.00), 15.00, false], # v4
|
||||||
[Vector3(210.00, 23.80, -504.00), Vector2(8.00, 8.00), 53.00], # v_lift
|
[Vector3(210.00, 23.80, -504.00), Vector2(8.00, 8.00), 53.00, true], # v_lift
|
||||||
]
|
]
|
||||||
|
|
||||||
# Ускоряющие полосы: центр на полу, размер (ширина, длина), рыскание (направление разгона), скорость
|
# Ускоряющие полосы: центр на полу, размер (ширина, длина), рыскание (направление разгона), скорость
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 MiB After Width: | Height: | Size: 4.3 MiB |
@@ -5,12 +5,12 @@ extends Area3D
|
|||||||
|
|
||||||
@export var size := Vector2(6.0, 10.0) # ширина (X) и длина (Z), м
|
@export var size := Vector2(6.0, 10.0) # ширина (X) и длина (Z), м
|
||||||
@export var speed := 22.0
|
@export var speed := 22.0
|
||||||
@export var color := Color(0.35, 0.9, 0.85) # холодный бирюзовый: отличается от жёлтых стрелок-подсказок трассы
|
@export var color := Color(0.85, 0.45, 1.0) # пурпурно-белый: отличается от ледяных стрелок-подсказок трассы
|
||||||
|
|
||||||
const SHADER := """
|
const SHADER := """
|
||||||
shader_type spatial;
|
shader_type spatial;
|
||||||
render_mode unshaded, blend_add, cull_disabled, depth_draw_never;
|
render_mode unshaded, blend_add, cull_disabled, depth_draw_never;
|
||||||
uniform vec4 tint : source_color = vec4(0.35, 0.9, 0.85, 1.0);
|
uniform vec4 tint : source_color = vec4(0.85, 0.45, 1.0, 1.0);
|
||||||
uniform vec2 dims = vec2(6.0, 10.0);
|
uniform vec2 dims = vec2(6.0, 10.0);
|
||||||
varying vec2 uv;
|
varying vec2 uv;
|
||||||
void vertex() { uv = VERTEX.xz; }
|
void vertex() { uv = VERTEX.xz; }
|
||||||
|
|||||||
+6
-2
@@ -6,7 +6,8 @@ extends Area3D
|
|||||||
|
|
||||||
@export var size := Vector2(6.0, 6.0) # сечение столба (X, Z), м
|
@export var size := Vector2(6.0, 6.0) # сечение столба (X, Z), м
|
||||||
@export var height := 14.0 # высота столба, м
|
@export var height := 14.0 # высота столба, м
|
||||||
@export var color := Color(0.45, 0.85, 0.35)
|
@export var color := Color(0.25, 0.95, 0.75)
|
||||||
|
@export var hidden := false # скрытый поток (шахта-лифт): только тёмная решётка, без столба, щелей и света
|
||||||
|
|
||||||
const SHADER := """
|
const SHADER := """
|
||||||
shader_type spatial;
|
shader_type spatial;
|
||||||
@@ -55,6 +56,7 @@ func _build_visuals() -> void:
|
|||||||
col.material_override = sm
|
col.material_override = sm
|
||||||
col.position.y = height * 0.5
|
col.position.y = height * 0.5
|
||||||
col.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
col.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||||
|
if not hidden:
|
||||||
add_child(col)
|
add_child(col)
|
||||||
# решётка на полу: тёмная плита с светящимися щелями
|
# решётка на полу: тёмная плита с светящимися щелями
|
||||||
var dark := StandardMaterial3D.new()
|
var dark := StandardMaterial3D.new()
|
||||||
@@ -67,11 +69,13 @@ func _build_visuals() -> void:
|
|||||||
var plate := BoxMesh.new()
|
var plate := BoxMesh.new()
|
||||||
plate.size = Vector3(size.x - 0.3, 0.08, size.y - 0.3)
|
plate.size = Vector3(size.x - 0.3, 0.08, size.y - 0.3)
|
||||||
_add(plate, dark, Vector3(0, 0.04, 0))
|
_add(plate, dark, Vector3(0, 0.04, 0))
|
||||||
var n := int((size.x - 0.8) / 0.7)
|
var n := 0 if hidden else int((size.x - 0.8) / 0.7)
|
||||||
for i in n:
|
for i in n:
|
||||||
var slit := BoxMesh.new()
|
var slit := BoxMesh.new()
|
||||||
slit.size = Vector3(0.22, 0.03, size.y - 1.0)
|
slit.size = Vector3(0.22, 0.03, size.y - 1.0)
|
||||||
_add(slit, glow, Vector3(-(size.x - 0.8) * 0.5 + (i + 0.5) * (size.x - 0.8) / n, 0.095, 0))
|
_add(slit, glow, Vector3(-(size.x - 0.8) * 0.5 + (i + 0.5) * (size.x - 0.8) / n, 0.095, 0))
|
||||||
|
if hidden:
|
||||||
|
return
|
||||||
# слабый свет над решёткой
|
# слабый свет над решёткой
|
||||||
var l := OmniLight3D.new()
|
var l := OmniLight3D.new()
|
||||||
l.light_color = color
|
l.light_color = color
|
||||||
|
|||||||
+2
-2
@@ -117,8 +117,8 @@ void fragment() {
|
|||||||
|
|
||||||
# Настройки чувствительности мыши
|
# Настройки чувствительности мыши
|
||||||
# --- Внешние эффекты карт (objects/vent.gd, objects/boost_strip.gd): локально, в сеть не уходят ---
|
# --- Внешние эффекты карт (objects/vent.gd, objects/boost_strip.gd): локально, в сеть не уходят ---
|
||||||
const VENT_ACCEL = 60.0 # Подъёмное ускорение в вентиляционном потоке
|
const VENT_ACCEL = 80.0 # Подъёмное ускорение в вентиляционном потоке
|
||||||
const VENT_MAX_RISE = 11.0 # Поток разгоняет вертикальную скорость не выше этой
|
const VENT_MAX_RISE = 16.0 # Поток разгоняет вертикальную скорость не выше этой
|
||||||
const BOOST_ACCEL = 60.0 # Разгон на ускоряющей полосе (потолок — MAX_SPEED)
|
const BOOST_ACCEL = 60.0 # Разгон на ускоряющей полосе (потолок — MAX_SPEED)
|
||||||
const EFFECT_HOLD = 0.12 # Сколько секунд эффект держится после последнего вызова (область зовёт каждый кадр)
|
const EFFECT_HOLD = 0.12 # Сколько секунд эффект держится после последнего вызова (область зовёт каждый кадр)
|
||||||
var vent_timer: float = 0.0
|
var vent_timer: float = 0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user