Я пытаюсь скопировать логику физического движка Sonic , который был написан для системы с фиксированным временным шагом (60 FPS), с переменным возрастом (Slick2D, если быть точным).
В оригинале после нажатия кнопки прыжка velocity.y
игрока устанавливается на -6,5, а каждый тик 0,21875 добавляется к velocity.y
для моделирования силы тяжести.
Каждый раз, когда вызывается мое обновление логики, передается параметр дельта времени, указывающий, сколько миллисекунд прошло.Если прошло больше миллисекунд, чем я ожидал, тогда я повторяю логику обновления, пропуская «внутреннюю дельту», которая не больше 1 или меньше, если мы имеем дело с «остатком» целевого кадра.
Например, если мы ожидаем, что кадр займет 16 мс, а делает 16 мс, цикл будет повторяться один раз и передаст thisMiniTick
как 1. Если дельта была не 16 мс, а 40 мс, цикл будетвыполнить три раза, пройдя 1, 1 и, наконец, 0,5.
Я ошибочно подумал, что в каждом из этих внутренних циклов обновления я мог бы сделать velocity.y += (gravity * thisMiniTickRelative)
, но это не работает.На более высоких частотах кадров применяется недостаточная гравитация, вызывающая более высокий скачок, а на более медленных кадровых показателях прыжок ниже (хотя и не так близко, как это заметно).
Есть ли способ сделать это, который будет работать практически для всех кадровых скоростейили я должен прибегнуть к установке верхней и нижней границ для delta
?
Цикл «внутреннего обновления»:
float timeRemaining = delta/1000f;
while(timeRemaining > 0)
{
float thisMiniTick = Math.min(timeRemaining, 1f / FRAMES_PER_SECOND);
float thisMiniTickRelative = thisMiniTick / (1f / FRAMES_PER_SECOND);
updateInput(container, game, thisMiniTickRelative);
if (playerAirState)
{
playerVelocity.y += (GRAVITY * thisMiniTickRelative);
}
clampPlayerVelocity();
playerPosition.add(playerVelocity);
doCollisions();
timeRemaining -= thisMiniTick;
}