Базовая гравитационная реализация в OpenGL - PullRequest
0 голосов
/ 27 марта 2019

Я пытаюсь реализовать прыжки в моей игре OpenGL. Мои левая и правая «скорость» и «трение» работают хорошо, но я не могу заставить свой прыжок работать по хорошей дуге. Игрок застревает в воздухе:

void keyboard() {
    //Move Left
    if (GetAsyncKeyState(keyA)) {
        playerVelX -= 3;
    }
    //Move Right
    if (GetAsyncKeyState(keyD)) {
        playerVelX += 3;
    }
    //Jump
    if (GetAsyncKeyState(keySpace)) {
        playerVelY += 3;
    }
}

void position() {
    //Move on x and y axis
    playerX += playerVelX;
    playerY += playerVelY;

    //Slow down respective axes
    playerVelX *= friction;
    playerVelY *= gravity;
}

while(gameRunning) {
    keyboard();
    position();
}

Я думаю, что смотрю на это слишком долго. У кого-нибудь есть опыт реализации гравитации, подобной этой? Спасибо

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Ваша формула для применения гравитации неверна.Помните, что F=m.a, v=v_0+ a*t, x=x_0 +v_0*t + 0.5*a*t^2.Но обычный подход заключается в использовании метода Эйлера для численного интегрирования:

gravity=9.81;
velocity+=gravity*deltaT;
position+=velocity*deltaT;

В вашем коде это будет выглядеть так:

playerVelX *= friction;
playerVelY -= gravity;//If Y point up, so gravity acts against that.

playerX += playerVelX;
playerY += playerVelY;

Если вы хотите иметь детерминистическое и стабильное моделирование (котороевы должны) тогда вам нужно иметь deltaTime - сколько времени прошло с момента последнего обновления.Смотрите эту отличную статью Исправьте свой Timstep! .Кроме того, приведенный выше код постоянно применяет гравитацию, даже когда не прыгает, так что имейте это в виду.

0 голосов
/ 27 марта 2019

Суммируя все неточности:

  1. Очевидная ошибка m * dv/dt = -m * g так dv = -g * dt так playerVelY -= gravity * dt
  2. В прыжке дальнейшее отталкивание невозможно, поэтому

    if (GetAsyncKeyState(keySpace) && (playerY <= groundLevel)) {
        playerVelY += 3;
    }
    
  3. Гравитация не должна действовать, если игрок находится на поверхности.

    if (playerY < groundLevel)
    {
       playerY = groundLevel;
       playerVelY = 0; 
    }
    

    Более реалистично учитывать силу реакции.

  4. Ваша модель playerVelX *= friction; соответствует вязкому трению. Игрок никогда не остановится. Вы уверены, что вам нужно вязкое, а не сухое трение?

  5. dt следует определять как реальное время между обновлениями, в противном случае результат будет зависеть от текущей частоты обновления. Вам нужно что-то вроде

    void position() {
       static double lastTime = getCurrTime();
       double currTime = getCurrTime();
       double dt = currTime - lastTime;
    
       playerX += playerVelX * dt;
       playerY += playerVelY * dt;
    
       if (playerY < groundLevel)
       {
           playerY = groundLevel;
           playerVelY = 0; 
       }
    
       //Slow down respective axes
       playerVelX *= exp(-friction * dt); // playerVelX *= (1 - friction * dt) for small dt
       playerVelY -= gravity * dt;
    
       lastTime = currTime;
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...