Я использую дельта-время, чтобы сделать частоту кадров моей программы независимой.
Однако я не могу получить высоту прыжка, она будет одинаковой, персонаж всегда прыгает выше при более низкой частоте кадров.
Переменные:
const float gravity = 0.0000000014f;
const float jumpVel = 0.00000046f;
const float terminalVel = 0.05f;
bool readyToJump = false;
float verticalVel = 0.00f;
Логический код:
if(input.isKeyDown(sf::Keyboard::Space)){
if(readyToJump){
verticalVel = -jumpVel * delta;
readyToJump = false;
}
}
verticalVel += gravity * delta;
y += verticalVel * delta;
Я уверен, что дельта-время правильное, потому что персонаж движется горизонтально хорошо.
Как заставить моего персонажа прыгать одинаково, независимо от частоты кадров?
Формула для расчета новой позиции:
position = initial_position + velocity * time
С учетом силы тяжести, которая уменьшает скорость в зависимости от функции:
velocity = initial_velocity + (gravity^2 * time)
ПРИМЕЧАНИЕ: сила тяжести в этом случае не совпадает с силой тяжести.
Окончательная формула становится:
position = initial_position + (initial_velocity + (gravity^2 * time) * time
Как видно из приведенного выше уравнения, на initial_position и initial_velocity не влияет время. Но в вашем случае вы фактически устанавливаете начальную скорость, равную -jumpVelocity * delta
,
Чем ниже частота кадров, тем больше значение delta
будет, и, следовательно, персонаж будет прыгать выше. Решение состоит в том, чтобы изменить
if(readyToJump){
verticalVel = -jumpVel * delta;
readyToJump = false;
}
в
if(readyToJump){
verticalVel = -jumpVel;
readyToJump = false;
}
РЕДАКТИРОВАТЬ:
Вышесказанное должно дать довольно хорошую оценку, но это не совсем правильно. При условии, что p(t)
позиция (в данном случае высота) после времени t
, тогда скорость определяется v(t) = p'(t)', and the acceleration is given by
a (t) = v ‘(t) = p’ ‘(t) `. Поскольку мы знаем, что ускорение является постоянным; т.е. под действием силы тяжести мы получаем следующее:
a(t) = g
v(t) = v0 + g*t
p(t) = p0 + v0*t + 1/2*g*t^2
Если мы теперь посчитаем p(t+delta)-p(t)
Т.е. при смене позиции от одного экземпляра во времени к другому мы получаем следующее:
p(t+delta)-p(t) = p0 + v0*(t+delta) + 1/2*g*(t+delta)^2 - (p0 + v0*t + 1/2*g*t^2)
= v0*delta + 1/2*g*delta^2 + g*delta*t
Оригинальный код не учитывает возведение в квадрат delta
или дополнительный срок g*delta*t*
, Более точным подходом было бы сохранить увеличение дельты, а затем использовать формулу для p(t)
дано выше.
Образец кода:
const float gravity = 0.0000000014f;
const float jumpVel = 0.00000046f;
const float limit = ...; // limit for when to stop jumping
bool isJumping = false;
float jumpTime;
if(input.isKeyDown(sf::Keyboard::Space)){
if(!isJumping){
jumpTime = 0;
isJumping = true;
}
else {
jumpTime += delta;
y = -jumpVel*jumpTime + gravity*sqr(jumpTime);
// stop jump
if(y<=0.0f) {
y = 0.0f;
isJumping = false;
}
}
}
ПРИМЕЧАНИЕ: я не скомпилировал и не протестировал код выше.
Под «дельта-временем» вы подразумеваете переменные временные шаги? Как в каждом кадре вы вычисляете временной шаг, который может полностью отличаться от предыдущего?
Если так, НЕ.
Прочитай это: http://gafferongames.com/game-physics/fix-your-timestep/
TL; DR: использовать фиксированные временные шаги для внутреннего состояния; интерполировать кадры, если это необходимо.