Тактический отряд с автоматическим огнём в изометрии, собственный софтверный растеризатор (raylib только окно, ввод и финальный блит). Ядро (спек, раздел 6): - LaneClear: проверка линии огня по своим, стенам и дальности; - решатель огневых позиций с гистерезисом и коммитом; - резервирование линий огня и расступание из чужих секторов; - пули-снаряды, дружественный урон физически возможен. Хоррор-слой (render-only): свет и туман войны с памятью карты, светящиеся трассеры, кровь, виньетка, зерно, напряжение. Ближний бой: сектор удара, три фазы, связка из трёх ударов, своя дисциплина «не бить сквозь своего». Проверка: squad_proto.exe --accept прогоняет критерии приёмки раздела 11 плюс блок M7 по ближнему бою — все PASS, FRIENDLY_HITS = 0 за 3 минуты боя. Сборка: cmake -S . -B build && cmake --build build --config Release raylib 6.0 подтягивается через FetchContent. Документация — CLAUDE.md как оглавление, содержание в docs/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
151 lines
11 KiB
Markdown
151 lines
11 KiB
Markdown
# 06 — Оверлей, метрики, тюнинг
|
||
|
||
## Оверлей
|
||
|
||
[src/debug/overlay.cpp](../src/debug/overlay.cpp). Рисуется примитивами raylib **поверх**
|
||
уже отмасштабированного кадра. Это единственное исключение из «вся сцена софтверная»,
|
||
и оно dev-only: `F1` его убирает.
|
||
|
||
| Клавиша | Что показывает |
|
||
|---|---|
|
||
| `F1` | оверлей целиком |
|
||
| `F2` | линии огня |
|
||
| `F3` | кандидаты последнего прогона решателя |
|
||
| `F4` | метрики |
|
||
| `F5` | выключить хоррор-слой целиком (свет, туман, пост) |
|
||
| `F6` | показать диски обзора |
|
||
|
||
Всегда (при включённом `F1`): якорь отряда, **два** круга когезии (синий —
|
||
стрелков, оранжевый — клинков), слоты строя, подпись над каждым агентом
|
||
`индекс, класс (R/M), состояние (A/H), id цели` и у клинка фаза удара
|
||
(`wind` / `HIT` / `rec`), выбранная огневая позиция `postPos` кружком.
|
||
|
||
**Сектор клинка**: кольцо досягаемости и две границы дуги, цвет по фазе —
|
||
жёлто-оранжевый на замахе, белый на ударе, серый на восстановлении. В покое цвет
|
||
говорит, почему не бьём: жёлтый — свой в дуге, синий — просто ждёт.
|
||
|
||
**Цвета линий огня (`F2`)**:
|
||
|
||
| Цвет | Значение |
|
||
|---|---|
|
||
| зелёный | линия чиста, агент стреляет |
|
||
| жёлтый | цель есть, линию перекрыл свой |
|
||
| красный | линию перекрыла стена |
|
||
|
||
**Кандидаты (`F3`)**: точками, цвет по оценке (синий низкая → белый высокая),
|
||
отбракованные — тусклым красным, выбранный обведён белым кругом.
|
||
Показывается последний прогон решателя, поэтому у агентов, у которых линия есть,
|
||
там пусто — решатель для них не запускался, так и задумано.
|
||
|
||
В ручном режиме дополнительно рисуется вектор прицела, границы конуса ±20°
|
||
и обводка назначенной цели.
|
||
|
||
## Метрики (`F4`)
|
||
|
||
[src/debug/metrics.h](../src/debug/metrics.h).
|
||
|
||
| Метрика | Как считается | Смысл |
|
||
|---|---|---|
|
||
| **FRIENDLY_HITS** | накопительный счётчик попаданий пуль по своим | главная метрика корректности, должна быть 0 |
|
||
| **FIRE UPTIME** | доля шагов с валидной линией за окно 10 с; среднее — **только по стрелкам** | насколько отряд «в деле» |
|
||
| **MELEE reach** | доля шагов с целью в зоне удара, среднее по клинкам | то же самое для ближнего боя |
|
||
| `swings / hits / aborted` | взмахов начато, попаданий лезвием, взмахов оборвано своим в дуге | `aborted` — видимая цена скученности, не баг |
|
||
| **SETTLE TIME** | от перехода в `HOLDING` до момента, когда ≥4 агента «в бою» | как быстро расходится веером |
|
||
| fps, `sim ms/frame` | время симуляции за кадр | бюджет 16.6 мс |
|
||
|
||
«В бою» для стрелка — валидная линия, для клинка — выбранная цель. Смешивать
|
||
доли времени двух разных занятий в одно среднее бессмысленно, поэтому
|
||
`FIRE UPTIME` и `MELEE reach` считаются раздельно: у клинка линии огня не бывает
|
||
по определению, и его ноль занижал бы метрику стрельбы.
|
||
|
||
Реализация `FIRE UPTIME` — кольцевой буфер на 600 сэмплов на агента с
|
||
инкрементальными счётчиками, пересчёт O(1) за шаг.
|
||
|
||
**Журнал попаданий по своим**: каждое попадание пишется в `Metrics::hitLog`
|
||
(время, стрелок, жертва, координаты, состояние жертвы). Без него `FRIENDLY_HITS != 0`
|
||
нечем объяснить — именно журнал показал, что жертва всегда была `ADVANCING`,
|
||
и вывел на настоящую причину (см. [08-decisions.md](08-decisions.md)).
|
||
|
||
### Как читать цифры
|
||
|
||
- `FIRE UPTIME` считает «нет живой цели в радиусе» как простой. Поэтому на
|
||
переходах между комнатами и после зачистки кучки метрика честно падает — это не
|
||
дефект ИИ. Критерий приёмки 11.8 относится к **стоячему бою рядом с мишенями**.
|
||
- `SETTLE TIME` по той же причине растёт, если отряд остановился там, где стрелять
|
||
не по чему. Сценарий `--accept` меряет его в правильной обстановке.
|
||
|
||
## Runtime-тюнинг
|
||
|
||
Все числа живут в [src/tuning.h](../src/tuning.h) в структуре `Tuning`.
|
||
Магических констант по коду нет — если нужно новое число, оно добавляется туда.
|
||
|
||
Часть параметров вынесена в таблицу `TUNABLES` и крутится на ходу:
|
||
|
||
- `[` / `]` — выбрать параметр, текущее имя и значение видно в оверлее;
|
||
- `-` / `=` — изменить с шагом параметра (с зажатием работает автоповтор).
|
||
|
||
Те же параметры можно задать из командной строки без пересборки:
|
||
|
||
```bash
|
||
squad_proto.exe --headless 300 --set safetyMargin=0.25 --set laneReserve=2.0
|
||
```
|
||
|
||
Список параметров смотри прямо в `TUNABLES` — там имя, поле, шаг и границы.
|
||
|
||
Самые содержательные для ощущения:
|
||
|
||
| Параметр | На что влияет |
|
||
|---|---|
|
||
| `safetyMargin` | запас к «телу в линии»; шире → реже стреляют, но безопаснее |
|
||
| `laneReserve` | во сколько раз резерв линии шире порога блокировки; отвечает за «текучесть» |
|
||
| `wLaneAvoid` | насколько нагло агент выдавливается из чужого сектора |
|
||
| `hysteresis` | насколько лучше должна быть новая позиция, чтобы агент переехал |
|
||
| `commitTime` | сколько держится решение; меньше → живее и дёрганее |
|
||
| `sDistCost` / `sCohesionCost` | готовность отбегать далеко ради выстрела |
|
||
| `postLeash` | жёсткая граница огневой позиции от диска; ниже — отряд плотнее |
|
||
| `anchorSpeed` / `anchorLeash` | отзывчивость диска и насколько он может оторваться от отряда |
|
||
|
||
Ближний бой (подробности — [11-melee.md](11-melee.md)):
|
||
|
||
| Параметр | На что влияет |
|
||
|---|---|
|
||
| `meleeReach` / `meleeArc` | размер сектора удара; шире → чаще задевает нескольких, но и своих |
|
||
| `meleeWindup` / `meleeStrike` / `meleeRecover` | ритм удара: читаемость замаха против скорострельности |
|
||
| `meleeInterval` / `meleeDamage` | DPS клинка |
|
||
| `meleeLunge` / `meleeKnock` | вес удара: рывок бойца и отдача мишени |
|
||
| `meleeCohesion` | СВОЙ, больший круг клинка вокруг диска |
|
||
| `meleeAllyMargin` / `meleePredict` | строгость дисциплины сектора; выше → меньше оборванных взмахов и меньше взмахов вообще |
|
||
| `meleeReserve` | насколько широко клинок отжимает своих со своей дуги |
|
||
| `meleeShake` | отдача камеры на попадание лезвием |
|
||
|
||
Хоррор-часть (подробности — [10-atmosphere.md](10-atmosphere.md)):
|
||
|
||
| Параметр | На что влияет |
|
||
|---|---|
|
||
| `sightRadius` / `sightCone` | как далеко и как широко видит отряд |
|
||
| `sightPersonal` | круговой ореол вокруг агента, спасает от клаустрофобии |
|
||
| `fogMemory` | насколько тускло помнится уже увиденное |
|
||
| `fogReveal` | при каком свете показывается тело мишени |
|
||
| `lightGamma` / `lightGain` | форма затухания света; **перепекают таблицу рампы** |
|
||
| `flashPower` | насколько вспышка выстрела освещает окружение |
|
||
| `fxIntensity` / `tracerLength` | яркость и длина трассеров |
|
||
| `grainTense` / `vigDepthTense` | зерно и виньетка на пике напряжения |
|
||
| `dreadRadius` | с какой дистанции мишень начинает пугать |
|
||
| `shakePerShot` | отдача камеры |
|
||
|
||
`F5` — аварийный тумблер: мгновенно возвращает прежний кадр без света и тумана.
|
||
Полезен, когда непонятно, баг это или просто темно.
|
||
|
||
## Dev-тумблеры ядра
|
||
|
||
`--no-solver` и `--no-laneavoid` выключают решатель и расступание. Это A/B-проверка
|
||
ценности ядра, цифры за 60 с на одном маршруте:
|
||
|
||
| Конфигурация | FRIENDLY_HITS | FIRE UPTIME |
|
||
|---|---|---|
|
||
| ядро выключено | 1 | 13.6 % |
|
||
| ядро включено | 0 | 88 % (на стоянке у мишеней) |
|
||
|
||
`sim`/`render` в оверлее показывают время шага симуляции и время кадра рендера
|
||
раздельно: 2 мкс против 1.4–3.5 мс при бюджете 16.6 мс.
|