Question

I'm trying to make an asteroids clone and so far I've gotten my ship to fly. However it's speed is also dependent on FPS. So to mitigate that I've read that I'd have to multiply my control variables with deltaTime (time between frames if i gathered right). However when I tried implementing that the ship refused to move. I thought that it's due to possible implicit rounding to 0 (converting to int?) but there are no warnings issued. What am I doing wrong?

Here's how the code looks:

sf::Vector2f newPosition(0,0);
sf::Vector2f velocity(0,0);
float acceleration = 3.0f;
float angle = 0;
float angularVelocity = 5;
float velDecay = 0.99f;


sf::Clock deltaClock;

window.setFramerateLimit(60);
while (window.isOpen())
{
    sf::Time deltaTime = deltaClock.restart();
    sf::Event event;
    while (window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed || ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
            window.close();
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
    {
        if(velocity.x < 10)velocity.x += acceleration * deltaTime.asSeconds();
        if(velocity.y < 10)velocity.y += acceleration * deltaTime.asSeconds();
        angle = player.getRotation() - 90;
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
    {
        if(velocity.x > 0)velocity.x -= acceleration * deltaTime.asSeconds();
        else velocity.x = 0;
        if(velocity.y > 0)velocity.y -= acceleration * deltaTime.asSeconds();
        else velocity.y = 0;
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
    {
        player.rotate(-angularVelocity);
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
    {
        player.rotate(angularVelocity);
    }

    newPosition.x = player.getPosition().x + (velocity.x * cos(angle * (M_PI / 180.0))) * deltaTime.asSeconds();
    newPosition.y = player.getPosition().y + (velocity.y * sin(angle * (M_PI / 180.0))) * deltaTime.asSeconds();    
    player.setPosition(newPosition);

    velocity.x *= velDecay;
    velocity.y *= velDecay;

    window.clear();
    window.draw(background);
    window.draw(player);
    window.draw(debugText);
    window.display();
}
Was it helpful?

Solution

I cannot run your code, thus I cannot be 100% sure, but the following does not look correct:

Calculation of Velocity

velocity.x = (player.getPosition().x + (acceleration * cos(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));
velocity.y = (player.getPosition().y + (acceleration * sin(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));   

Try changing it to something like this:

velocity.x = (player.getVelocity().x + (acceleration * cos(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));
velocity.y = (player.getVelocity().y + (acceleration * sin(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));   

This is utilizing the simple physics equation vf = vi + a*t but in a x,y component fashion. I believe using Position.x and Position.y would totally throw off that equation.

Note: syntax wise, the code I gave you might not work. Put whatever code into player.getVelocity().x that will get you the current velocity of the player in the X direction. Do the same for the Y direction.

Setting of the new position

I cannot be sure if player.setPosition(velocity); is proper or not. If the setPosition function takes care of doing the following:

newPosition.x = oldPosition.x + (velocity.x/dt)

both in the x and y direction, then that should work.

But if it is simply doing:

newPosition.x = velocity.x

Then I believe this will be wrong and result in improper simulation.

Overall

There could be other mathematical errors in your code. Especially with how you are calculating acceleration. I did not double check this and at the moment I do not have time to. If you make the adjustments I mentioned and its still not working, throw me a comment and I can try looking more when I have the time. I have a game of my own to go work on right now.

Edit1:

Your code looks a lot better. From here, I would add code that changes your acceleration. Say hitting the w key will turn on "thrusters" which give you an acceleration of 2. The acceleration will degrade(go back towards zero)over TIME when no key is being pressed. Not per frame. Before you were multiplying by .99 per frame. Which means acceleration could be zero in half a second if you are getting 120 fps (totally possible in a simple game like this). You need to have it degrade based on your dt variable. Once it hits zero however, you will still have a positive velocity. Usually this velocity is degraded over time due to gravity, but being in space gravity would be very small compared to what you find on earth (-9.8m/s or -32 ft/s). So perhaps you could implement a gravity falloff on your velocity which is also calculated in time

OR

you could ignore gravity and allow them to hit the S key and apply a negative acceleration (-2) and then apply that to your velocity as you have done. This would allow for negative values to degrade your velocity and could be thought of as your ships turning on thrusters in the opposite direction.

Of course you can cheat as the game developer and prevent your velocity from ever going below zero(if you want the player to only move forward) And when you detect a velocity that is negative, set Velocity to 0 and acceleration to 0.

Note: the acceleration "degrading" will happen for both positive and negative, and it will "degrade" towards zero. You will have to tinker with these values and play test to see what feels right. Should acceleration degrade 1 per second? Should you even use the value of 2 and -2 as the acceleration values I mentioned earlier? 2 and -2 might work, but maybe 3 and -3 are better? These are all questions you get to answer yourself through testing it out.

I hope this gives you some more ideas and helps solve your question fully! Let me know how it goes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top