(Delta time) Получение 60 обновлений в секунду в Java
Я видел этот код несколько раз.
long lastTime = System.nanoTime();
final double ticks = 60D;
double ns = 1000000000 / ticks;
double delta = 0;
Приведенный выше код отнимает системное время и сохраняет его в lastTime
, 60 тиков должны соответствовать количеству обновлений в секунду.
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if(delta >= 1){
tick();
delta--;
}
Занимает now
и вычитает lastTime
, а затем преобразует его в наносекунды /60. Есть ли какая-то гарантия того, что разница во времени между now
а также lastTime
к nano более 60 приведет к тому, что дельта будет больше или равна 1, 60 раз в секунду? Я не могу понять почему tick();
будет работать около 60 раз в секунду. Из моих расчетов каждый раз, когда цикл запускается, дельта увеличивается на 0,0025 или около того.
3 ответа
Не зная, что в tick()
Я не могу быть уверен, но я предполагаю, что он также использует 60D
пытаться спать в течение правильного количества времени? Итак: нет, нет никакой гарантии, это то, что этот код должен исправить.
Это говорит "Если tick()
спал меньше, чем клещ, потом ничего не делал; если он спал на тик или больше, тик один раз ".
Предположительно, если тиканье пройдёт достаточно (например, 80 нс, а затем 80 нс, что означает, что 1-й цикл увеличивает тик, а второй увеличивает его на 2), то в конце концов будет другой цикл, который имеет только дельту 40 нс, заставляя все выравниваться.
Я прокомментировал код немного, чтобы показать вам более ясно, что происходит.
//Get the system time
long lastTime = System.nanoTime();
//Specify how many seconds there are in a minute as a double
//store as a double cause 60 sec in nanosec is big and store as final so it can't be changed
final double ticks = 60D;
//Set definition of how many ticks per 1000000000 ns or 1 sec
double ns = 1000000000 / ticks;
double delta = 0;
while(running){
//Update the time
long now = System.nanoTime();
//calculate change in time since last known time
delta += (now - lastTime) / ns;
//update last known time
lastTime = now;
//continue while delta is less than or equal to 1
if(delta >= 1){
//Go through one tick
tick();
//decrement delta
delta--;
}
Теперь я почти уверен, что это именно так, но я не могу сказать наверняка, не видя, что такое tick()
Это гарантирует, что метод tick() выполняется только 60 раз в секунду. Он называется дельта-таймингом и упоминается во всем игровом сообществе. Причина, по которой используется дельта-синхронизация, заключается в том, чтобы игры работали с одинаковой скоростью на всех платформах. Такие вещи, как физика и анимация в играх, должны работать с одинаковой скоростью, независимо от скорости системы. Если у вас медленная система, а в игре нет дельта-синхронизации, физика будет работать медленнее, чем если бы игра работала на быстрой системе.
Как это устроено
Выясните, сколько раз вы хотите обновить в секунду, в вашем случае это 60 раз в секунду.
найти разрешение языков встроенной функции времени. В вашем коде используется встроенная в Java функция System.nanotime(), которая возвращает длинное значение количества наносекунд, в течение которых система работала.
есть 1000000000 наносекунд в секунду, что означает, что разница во времени на один вызов функции tick() равна 1000000000/60. Что составляет примерно 16666666 наносекунд. Это означает, что всякий раз, когда вызывается tick(), программа будет ждать 16666666 наносекунд, прежде чем снова вызовет tick().
что вы должны сделать, это найти время между текущим кадром и последним кадром в наносекундах. Это значение, деленное на временной шаг (16666666), даст вам десятичный процент от того, сколько прошло необходимого времени. Если вы добавите этот десятичный процент к дельта-переменной, когда дельта-переменная>= 1, пройдет 1/60 секунды, что означает, что теперь программа может вызывать tick().
наконец, вы минус 1 от дельта-переменной. Причина, по которой вы не устанавливаете дельта-переменную в 0, состоит в том, что, возможно, был больший временной шаг, чем 1, и дельта-переменная будет выше 1, что означает, что вам придется учитывать это при следующем цикле и вызове поставить галочку()