PlayerAnimator — TODO
1. Вынести определение скорости в отдельный компонент (MotionSource)
Сейчас скорость считается дважды независимо — в JumpController и в MinimalLocomotion
(оба берут (pos − prevPos)/dt в локальных осях). Надо вынести это в один маленький компонент:
- отдаёт
HorizontalSpeed,LocalVelocity(x=стрейф, z=вперёд), может иVerticalVelocity; - оба скрипта читают из него, а не считают сами;
- главная цель — единственная точка подмены под сеть: на owner'е источник = дельта трансформа
(или ECM2
Character.GetVelocity()), на реплике = реплицированное значение. Аниматор при этом не меняется вообще.
Плюсы: убирает дублирование; делает сетевой фикс (см. ниже) drop-in.
2. Сетевая репликация (главная нерешённая проблема)
Сейчас всё работает от дельты Transform, синканного через NetworkTransform. Локально заметно лучше, чем на реплике. Причина: реплика анимируется от ИНТЕРПОЛИРОВАННОГО трансформа, а дифференцирование интерполяции даёт шумную/заниженную/лагающую скорость (см. README — «animate from intent, not motion»).
Конкретные симптомы на реплике:
- иногда мисы на стрейфах (направление/скорость касания читается не так, как локально);
- нельзя поставить узкие интервалы приземления run/walk — из-за шума дельты синка скорость гуляет
(спайки 5–7, провалы до 3–3.1), приходится держать интервалы широкими;
- ранний выход из LAND-RUN при продолжении бега: скорость временно проваливается ниже _runLandMin
(должна быть ~4, а из-за синка падает <3) → moving-ленд обрывается, хотя игрок продолжает бежать.
Локально этого нет.
План (после MotionSource)
- Оставить перемещение на NetworkTransform (позиция как есть).
- Реплицировать скорость owner'а (квантованный float/локальный вектор, ~15–20 Гц) и кормить её
в
MotionSourceна реплике. Скорость идёт ТОЛЬКО в аниматор, не в движение. - Дискретное слать как стейт/флаги, а не выводить из трансформа:
isSprinting(кнопка+стамина — им и разделять run/walk вместо интервалов скорости),jumpSeq(фронт прыжка). - Landing-триггер оставить локальным (свой grounded реплики), чтобы стопа вставала по её же телу, а не по таймлайну owner'а. Клип выбирать по реплицированной скорости.
Открытые вопросы
- Точность/частота квантования скорости (баланс трафик ↔ джиттер).
- Возможный рассинхрон «тело реплики уже на земле, а скорость-стейт ещё нет» — насколько заметен, нужен ли сглаживающий буфер на реплицированной скорости.
- Разделение sprint/walk точно уходит в стейт контроллера (кнопка+стамина); интервалы скорости — временная заглушка до этого.
- PurrNet из коробки ECM2 не поддерживает — сетевой слой пишем сами (отдельный
NetworkBehaviourс SyncVar поверхMotionSource), по аналогии с Mirror/Netcode примерами ECM2.
3. Мелочи
- Убрать
_debugLog-вызовы или оставить под флагом (сейчас под флагом — ок).