Извлечено из замороженного 20-explanation/simulation. Сам порядок держат тесты тик-ордера, здесь — причина каждого шага: без неё порядок выглядит произвольным, и его «упрощают».

Решили: шаг тика стоит на своём месте не по вкусу, а по конкретной поломке, которую он иначе даёт.

  • Brain (цель и намерение) — до движения. Иначе юнит идёт к цели, выбранной в прошлом тике: к мёртвой или к уже убежавшей.
  • Displacement и Separation — после обычного движения. Сначала юнит шагает к цели, потом накладываются отбрасывания и расталкивание; к перестройке хэша позиции финальные.
  • SpatialHash — после движения и до атак со снарядами, которые им пользуются. Строить раньше значит искать соседей по вчерашним позициям.
  • Вторая перестройка хэша — условная и обязательная. Блинк убийцы двигает тело уже ПОСЛЕ первой перестройки, и без повторной сетка врёт до конца тика: соседи находят блинкнувшего по-разному с двух зеркальных сторон. AutoAttackSystem.Tick возвращает признак «сдвиг был» — только тогда хэш строится снова.
  • Regen — перед Effects. Иначе реген «вытаскивает» юнита из летального DoT задним числом. У RegenSystem для этого же есть гард CurrentHP > 0.
  • CommitEffects — после дренажа событий и до смертей. После дренажа, чтобы реактивы успели наложить своё; до смертей, чтобы не пересчитывать трупы.
  • Death — в самом конце. Сначала весь урон тика, включая отложенные события шипов, потом единая обработка смертей.

Почему фиксированный шаг, а не Time.deltaTime: реальное время плавающее — один кадр 16 мс, другой 50. Считать бой по нему значит сделать исход зависящим от FPS игрока, то есть убить детерминизм. Симуляция всегда шагает ровно на 1/30.

Грабли — «спираль смерти», и она уже случалась. У цикла добора тиков раньше не было потолка. Кадр завис на полсекунды (сборка мусора, подгрузка) — в аккумуляторе 15 тиков; цикл гонит их за один кадр, кадр становится ещё длиннее, тиков ещё больше. Игра не «немного тормозит», а проваливается насмерть. Потолок на число тиков за кадр обязателен, и он не оптимизация, а страховка от расходящегося процесса.

Владелец правды: Assets/_Project/Scripts/Combat/CombatSimulation.cs (порядок систем в Tick()) и тесты тик-ордера; зеркальные сторожа — MirrorMatchTests и MirrorDivergenceProbe.