Почему положение объекта, полученное через Time.deltaTime, отличается от положения, полученного через таймер?
Я пытаюсь перемещать объект не плавно, а «ступенчато». Это означает, что я не использую Time.deltaTime в Update(). Вместо этого через равные промежутки времени я перемещаю объект на некоторое одинаковое расстояние. При этом я ожидаю, что на достаточно большом расстоянии от начала движения не должно быть разницы между способами перемещения. Однако я заметил, что через несколько итераций «пошаговое» перемещение начинает заметно отставать от перемещения с помощью Time.deltaTime.
Изначально я хотел сделать подобие анимированного плоттера с помощью LineRenderer, поэтому и возник вопрос о «ступенчатом» перемещении. Я заметил значительные отставания от ожидаемой скорости графика. В попытке выяснить суть проблемы я начал отбрасывать всё лишнее. В итоге я собрал простую сцену с двумя сферами. Для каждой из них написан похожий скрипт.
public class MoverDeltaTime : MonoBehaviour
{
private readonly float _step = 0.1f;
private readonly float _timeout = 0.1f;
private float _speed;
private void Start()
{
_speed = _step / _timeout;
}
void Update()
{
/* Здесь _speed * Time.deltaTime - расстояние, пройденное за время Time.deltaTime */
transform.Translate(_speed * Time.deltaTime * Vector3.left);
}
}
public class MoverTimed : MonoBehaviour
{
private readonly float _step = 0.1f;
private readonly float _timeout = 0.1f;
private float _lastTime;
void Update()
{
if (Time.time - _lastTime >= _timeout)
{
/* Здесь _step - расстояние, пройденное за время _timeout */
transform.Translate(_step * Vector3.left);
_lastTime = Time.time;
}
}
}
Очевидно, что _speed * Time.deltaTime - это расстояние, пройденное за время Time.deltaTime.
Но аналогично и _step во втором скрипте - это расстояние, пройденное за время _timeout.
В моем понимании, здесь одинаковый подход. Однако на практике между сферами растет расстояние. Это заметно на скриншоте (камера в ортографическом режиме, поэтому это не искажение).
В связи с этим меня мучают вопросы, почему так происходит? Я допустил какую-то глупую ошибку в рассуждениях? Я неверно понимаю принцип работы Time.deltaTime? Или всё дело в округлениях float-переменных? И как, собственно, правильно перемещать объекты «ступенчато»?
Ответы (1 шт):
transform.Translate(_step*Vector3.left);
А остаток времени извиняюсь спросить куда девается? Time.time-_lastTime > _step... где разница? типа она ничтожна?
Ты можешь потерять при 60 fps от 0 до 0,016 секунды в момент шага. При шаге раз в 0.1, то есть 10 раз в секунду теряешь по 0,008(среднее), в итоге 0,08 в секунду. Через всего 10 секунды ты потеряешь 0,8, почти целую секунду.
public class Move : MonoBehaviour
{
[SerializeField] private Vector3 _vector = Vector3.left;
private void Update ()
{
transform.position += _vector*Time.deltaTime;
}
}
public class MoveStep : MonoBehaviour
{
[SerializeField] private Vector3 _vector = Vector3.left;
[SerializeField] private float _timeStep = 0.1f;
private float _timer;
// test
[SerializeField] private Move _move;
private bool _isChange;
private void Update ()
{
_timer += Time.deltaTime;
if (_timer >= _timeStep)
{
transform.position += _vector*_timeStep;
_timer -= _timeStep;
_isChange = true;
}
}
// в конце кадра, когда Update обоих уже сработал
private void LateUpdate ()
{
if (_move != null && _isChange)
{
Debug.Log("M "+_move.transform.position);
Debug.Log("MS "+transform.position);
_isChange = false;
}
}
}

