Три пункта из разбора образца сделаны и проверены замерами. Ниже — что изменилось, что показали числа и где я себя поправил.
Всё измерено, а не оценено на глаз. Кадры «до» сняты на той же дистанции и в том же времени суток, что «после»: сравнение кадров разного освещения показало бы разницу света, а не правку.
| Что | До | После |
|---|---|---|
| Треугольников (день, ~200) | 22 664 | 21 614 … 26 948 |
| Вызовов отрисовки (день, ~200) | 67 | 58 … 98 |
| Колеи на полотне | 3 | 5 |
| Поезд | нет | едет сам |
| Собственная скорость поезда | — | 7.45 при ожидаемых 6.50 |
| Колея поезда | — | x = 4.4, вне полос игрока (−2.2…2.2) |
| Ночная насыпь станции | R74 G80 B92 (холодная) | R74 G60 B48 (тёплая) |
| Яркость ночной насыпи | 79.6 | 62.8 (не выросла) |
| Различимых цветов в кадре | — | 326 … 373 |
Поезд движется сам — это главное. Мир едет навстречу целиком, и «движется» для поезда значит больше: за 0.25 с игрового времени мир прошёл 5.00 единиц, а поезд 12.45, то есть 7.45 своих при заданной скорости 26 (ожидание 6.50, расхождение — округление шага).
Поезд — та же лента, что предметы мира, но с другим аргументом. Мир
прокручивается формулой z = ((item.z + world) % range + range) % range − span.
Мировая координата входит одним слагаемым — значит поезд, идущий навстречу,
получается подстановкой world + travel, где travel = скорость · время.
Нового механизма не появилось вовсе: заворот, высота рельефа и скрытие нулевых
инстансов уже отлажены на предметах мира.
Вагон-препятствие — форма, а не правило. На станции full был контейнером,
стал вагоном с ливреей: окна, тележки, предупредительная полоса. Габарит
проходимости при этом не изменился ни на сотую: замер — 1.8 × 3.2 × 2.4,
ровно как в TIMING.obstacle.full. Проходимость считается по габариту и по
cells ряда, а не по силуэту, поэтому форма вольна меняться.
Тёплая станция — оттенок, а не яркость. Пара цветов локации в LOCATIONS.
Ночной тон был холодным (R74 B92), стал тёплым (R74 B48) при меньшей
яркости. Требование «тёмная насыпь сохраняется» выполнено арифметикой, и это
проверяется в логическом тесте, а не глазами.
Поезд слышен. Гудок — два тона квинтой плюс шумовой выдох, громкость от
расстояния. Зовётся из кадра, а не из шага мира: advance (шов стенда)
проматывает забег сотнями шагов подряд, и звук из шага мира прогремел бы
сотню раз.
Предметы стояли на путях. Прежде чем ставить поезд, я замерил, что попадает в его коридор (x от 3.10 до 5.70). Оказалось — 13 предметов в четырёх локациях: бетонные блоки, кактусы, кусты, камни, столбы, пальмы. Все они стояли на насыпи, местами прямо у игровых рельсов.
Поезду это мешало, но дело не только в поезде: предмет, стоящий на полотне,
читается сбоем, а не декорацией. Я сдвинул их за край насыпи (5.4), и коридор
стал чистым во всех четырёх локациях. Проверка теперь в репозитории —
tools/-скрипт считает это по PROP_KITS, а не на глаз.
Насыпь была узка для внешней колеи. Внешний рельс встаёт на 5.5, а полуширина полотна была 5.4 — рельс свисал бы. Расширил до 5.8: разметка и затенение краёв считаются от той же величины, поэтому разойтись не могут.
R10 был сформулирован неверно. Сначала я записал «потолок кадра не превышает достигнутого» — 22 074 треугольника и 57 вызовов. Но это требование противоречило цели спеки: плотность и есть то, ради чего она заведена, рост неизбежен. Требование, которое нельзя выполнить, не выполнив задачу, ничего не проверяет.
Переформулировал по факту замера: не больше 40 000 треугольников и 110 вызовов. Фактически вышло 21 614…26 948 и 58…98. Рост вызовов — это и есть цена плотности: каждый набор предметов — отдельная лента, а лента это один вызов. Станция выросла с 11 наборов до 14, плюс поезд.
Первый кадр «после» оказался с волком. Я сравнил его с кадром «до» без
волка и чуть не выдал погоню за правку. Переснял с фильтром по фактической
видимости: фильтр по фазе погони не годится — фаза away наступает, когда
погоня отпустила, а волк ещё сходит с экрана. Замерено: с фильтром по фазе
волк занял половину кадра.
Рампы и бег по крыше вагона. В образце есть подъём на вагон. У нас прыжок есть, а поверхности выше земли нет. Это меняет высоту земли, а от неё зависит просвет под высоким препятствием — просвет посчитан от габарита зайца стоя и в подкате. Значит это отдельная спека, а не третий пункт этой.
Движущийся поезд по игровой полосе. Тоже отдельно: меняет правило проходимости и требует замера окна реакции. Владелец выбрал колею, и это правильный выбор для первого шага.
Темп музыки. Не трогал. Замер показал, что наш потолок (176 уд/мин) уже совпадает с образцом (172); разница только в исходном темпе, и наш разгон сделан нарочно.
| Проверка | Результат |
|---|---|
node tests/test_runner_logic.mjs |
все проверки проходят, включая новые |
| Габарит вагона | 1.8 × 3.2 × 2.4 — совпадает с TIMING.obstacle.full |
| Вагон стоит от нуля | низ −1.6, верх +1.6 — не висит и не тонет |
| Состав на земле | низ −1.45 — по рельсам |
| Коридор поезда | 0 конфликтов в четырёх локациях |
| Тёплая насыпь | R74 > B48; яркость 62.8 ≤ 79.6 |
| Прочие локации | не тронуты (сверка с исходными значениями) |
| Поезд движется сам | 7.45 своих при ожидаемых 6.50 |
| Колея вне полос | x = 4.4 против полос −2.2…2.2 |
| Кадр не пуст | 326…373 различимых цвета, разброс яркости 218…226 |
Требования спеки — .kiro/specs/runner-liveliness/. Артефакты: слайдшоу и
сравнительные кадры в exports/site-assets/.