Боты и очередь старта
В небе, кроме самого пилота, летают «другие пилоты» — боты. Они не привязаны к маршруту, просто летают: ищут термики, парят у склона, перелетают от одной цели к другой. Половина из них уже в воздухе, когда начинается полёт — небо не пустое с первой секунды. В сетевой игре те же боты видны всем, и на старт выстраивается общая очередь: сначала живые пилоты, потом боты.
Кто такие боты
Число ботов — настройка «Другие пилоты в небе», 0–20 (bots.count, по умолчанию 4, действует со следующего полёта). У каждого бота своё крыло (случайно из списка configs/bots.json → wings, все примерно поровну; советские крылья в небе редкость — только «Апогей»), масса пилота 65–95 кг и расцветка паруса из палитры без брендов (красный, оранжевый, жёлтый, зелёный, бирюзовый, синий, фиолетовый, малиновый, графит). Все параметры — от сида полёта (configs/bots.json → seed, смешивается с местом старта), поэтому один и тот же полёт (то же место, сид) даёт одних и тех же ботов.
Модель полёта у ботов та же, что у игрока — FlightModel и Atmosphere.air_velocity_at, — просто шаг физики реже, если бот далеко: 30 Гц рядом с игроком (< 1500 м) и на земле, 10 Гц дальше, 4 Гц дальше 4000 м.
Как боты летают
«Мозги» бота — BotPilot (scripts/game/bot_pilot.gd), тот же класс, что у бота-маршрутника из исследований проходимости трасс (docs/plan/atmosphere). Бот «чувствует» только то, что доступно живому пилоту: вариометр, высоту, AGL, курс, крен, позицию, путевую скорость — карту термиков атмосферы (thermals_near) не подглядывает. Режимы полёта:
- CRUISE — переход по расчёту МакКриди;
- ENTER — усреднённый вариометр выше порога (0,5 м/с сверх собственного снижения; в режиме «спасения» ниже — 0,3 м/с) → вираж 35–40° в сторону, где был подъём;
- CIRCLE — центровка термика по правилу Райхмана (сильнее подъём — площе вираж, слабее — круче, круг сдвигается к максимуму), крен 8–50° (номинально 38°), карта подъёма помнится 12 с;
- PROBE — проверка стороны термика после «пощупал и потерял»;
- RIDGE — «восьмёрка у склона»: два смежных витка над одной рабочей точкой, разворот всегда от склона к долине; включается, если встречный ветер на старте ≥ 4 м/с, парит 60–300 с (случайно) или пока не наберёт 250 м над стартом, затем уходит в перелёты; ниже 25 м AGL уходит от склона в долину;
- ниже 300 м AGL — режим «спасения»: скорость минимального снижения, берёт любой подъём, порог входа ниже обычного.
Без цели («другие пилоты в небе», класс WanderPilot, scripts/game/wander_pilot.gd) бот перелетает между случайными точками в круге радиусом 3500 м вокруг старта (перелёт 800–2500 м, первый — 1200 м от склона в долину по курсу старта); если в конфиге включено — цель перелёта выбирается под растущим облаком в секторе ±30° от курса, как пилот читает небо. В одном термике кружат в одну сторону — её задаёт первый, кто вошёл (это может быть и игрок): круги ближе 300 м к центру «занятого» термика в последние 60 с считаются тем же термиком.
Боты расходятся друг с другом и с игроком по прогнозу сближения (configs/bots.json → separation, проверка 4 раза в секунду): не ближе 50 м по горизонтали и 15 м по высоте друг с другом (прогноз на 12 с вперёд), не ближе 90 м по горизонтали и 30 м по высоте от игрока (прогноз на 20 с) — столкновений ботов с игроком в игре нет вообще. Ниже 25 м AGL (разбег, посадка) расхождение не считается — там всё равно занята земля.
Имена над ботами
Над каждым ботом — табличка с именем (NameTag, Label3D-билборд): постоянный размер на экране (22 пикс. при высоте окна 1080, дальше — пропорционально FOV), полностью видно до 250 м, гаснет к 900 м (на земле — уже к 120 м, чтобы не рябило на старте), за рельефом не видно (табличка пишет глубину). Имена — из configs/bot_names.json, отдельный пул на каждый язык интерфейса (ru, en), без повторов в одном полёте, порядок — от сида полёта; при смене языка боты сразу берут имена из нового пула в том же порядке. Настройка «Имена пилотов» (bots.names.show, по умолчанию включена) применяется сразу, даже из паузы.

Настройка в экране «Настройки»:

Половина уже в воздухе
Если сразу поставить всех ботов в очередь на старт позади игрока, первым лететь в пустое небо скучно. Поэтому половина ботов (округление вниз, но не меньше одного — при одном боте в воздухе будет он) к началу полёта уже кружит впереди старта: 0e07d62. Появляются они 250–700 м впереди старта по курсу разбега, в стороны — до 300 м, по высоте — 200–450 м над рельефом (и не ниже старта плюс этот запас), с курсом ±60° от курса старта — случайно, но детерминированно (сид полёта). Остальные боты ждут в очереди на старт за игроком и взлетают после его отрыва.
Очередь на старт
Боты, ожидающие на земле, стоят с крылом на ровных площадках позади старта — не в коридоре разбега игрока, не у камней, кустов и деревьев (scripts/game/bot_pilots.gd → find_spots): перебор сетки с шагом 3 м, площадки не круче 8° (не хватает — 14°, затем любые), не ближе 12 м друг к другу (размах крыла ~10 м) и не ближе 9 м к игроку. Пока игрок на земле — боты ждут; после его отрыва боты выходят на старт по одному раз в 30 с (launch.interval_s) и разбегаются той же механикой, что и игрок (BotAgent). Сел не долетев или разбился — бот стоит минуту (landed_stand_s), затем убирается и снова встаёт в очередь.
В сетевой игре очередь общая для живых пилотов и ботов (scripts/game/net_queue.gd, NET-43): места ожидания те же, что у ботов в одиночной игре (место 0 — сам старт), но правила — как у живой очереди на настоящем старте:
- Сначала живые пилоты, потом боты. Живой, вернувшийся в очередь, встаёт перед первым ботом (кроме бота, который уже идёт на старт или бежит первым — его не сдвигают).
- Бежать может только первый. У остальных разбег заблокирован, пока они не станут первыми; взлетел — следующий шагает вперёд.
- Простоял первым дольше минуты — в конец. Чтобы никто не держал всю очередь, застряв на месте.
- После посадки, аварии или сорванного старта — в конец текущей очереди (перед ботами; если очередь пуста — сразу первым). Это осознанно: лёгкое наказание за неудачный старт и живая очередь, как на настоящем старте — не «баг для починки».
- Обходов очереди нет: если очередь мешает, решение — создать сетевую зону без ботов (0 в настройках) и взлетать друг за другом.
Очередь ведёт ведущий зоны (не путать со «старшим» в бытовом смысле — это тот, кто технически держит часы и рассылает ZoneState.queue раз в секунду): он не спрашивает остальных клиентов, а сам видит их фазы (стоит/идёт рядом со стартом — в очереди; бежит — в очереди, не трогать; в воздухе, на буксире, сел, разбился или ушёл дальше 250 м от старта — вне очереди). Каждый клиент сам идёт к своему месту по номеру в очереди; при смене ведущего новый продолжает с последней разосланной очереди, а таймер простоя первого начинается заново.

Границы модели
- Столкновений ботов с игроком нет вообще (расхождение только «на бумаге» — по прогнозу сближения); столкновения бот-бот не проверялись отдельно, расхождение то же 50 м/15 м.
- Посадки у ботов формально нет: касание земли — не авария и не полноценная посадка, а пауза на минуту с последующей постановкой в очередь.
- Обход рельефа сбоку и настоящее лавирование между несколькими термиками одновременно не моделируются — только вход/центровка/выход по вариометру, как у честного бота-маршрутника (без подглядывания в карту термиков).
- «Восьмёрка у склона» включается по одному порогу — встречному ветру на старте ≥ 4 м/с; боковой и попутный ветер на старте отдельно не учитываются.
- Обходных путей в очереди нет намеренно (см. выше) — это игровое решение, а не недосмотр.
Что рассматривали и почему так
- Все боты в очереди с самого начала — отклонили: первым лететь в пустое небо неинтересно, добавили «уже в воздухе» половину (
0e07d62). - Приоритетный вход без очереди («догнать» друга без ожидания старта) — реализован отдельно как механика «Догнать», а не как обход очереди на старт: сама очередь на старт правил не имеет исключений.
- Настоящая посадка у ботов (с ЛП, разбором полёта) — не сделана: минута паузы после касания земли проще и не требует у бота логики захода на посадку.
Подробнее
- docs/guide/game.md — раздел «Другие пилоты» и командная строка (
--bots=<N>,--look-at=bots). - scripts/game/bot_pilots.gd — управление ботами: появление, очередь на старте,
_start_airborne. - scripts/game/bot_pilot.gd — «мозги» бота: режимы, центровка, восьмёрка у склона.
- scripts/game/wander_pilot.gd — полёт без цели («другие пилоты в небе»).
- scripts/game/net_queue.gd — очередь на старт в сети (NET-43).
- configs/bots.json, configs/bot_names.json — все числа и пул имён.
- docs/plan/multiplayer.md — п. 6–7 (боты и очередь в сетевой игре).
0e07d62— половина ботов уже в воздухе на старте полёта.