Извлечено из замороженного
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.