SFML community forums

Help => General => Topic started by: TXRSTXN on February 07, 2016, 10:54:11 pm

Title: Timebased movement not working..
Post by: TXRSTXN on February 07, 2016, 10:54:11 pm
Okay, so I have been sitting for the last two days trying to work this out but it just wont work!

I am basically moving a circle relative to time. In this case I am  trying to make it move 100 px / second.
The problem is that the circle is moving really slow, and not 100 px / second at all. I have tried all kinds of ways to make it work but it's still not behaving as it's supposed to.

Can someone tell what I'm doing wrong?


int main() {
   
    sf::RenderWindow window(sf::VideoMode(700, 700), " ");
    sf::CircleShape circle(20);


    sf::Clock clock;        // Declaring clock, time and variable to measure the time.
    sf::Time time;
    double elapsed;


    while (window.isOpen()) {

        clock.restart();              // Restarting the clock.


        sf::Event event;
       
        while (window.pollEvent(event)){             // Event loop.
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }


        time = clock.getElapsedTime();        //Measuring time and moving the circle based on passed seconds.
        elapsed = time.asSeconds();
        circle.move(100*elapsed, 0);


        window.clear();
        window.draw(circle);
        window.display();
    }

    return 0;
}

 
Title: Re: Timebased movement not working..
Post by: GraphicsWhale on February 07, 2016, 11:36:56 pm
Try resetting the clock at the same time you get the time elapsed. You're currently measuring just the time it takes to poll events, not the time it takes to complete a full game loop.

Also:

- sf::Time::asSeconds returns a float, sf::CircleShape::move takes a float, why are you using a double?
- It's preferred to update a fixed amount at fixed time intervals rather than multiplying by the time passed.
Title: Re: Timebased movement not working..
Post by: Hapax on February 08, 2016, 12:53:49 am
As GraphicsWhale said:
Try resetting the clock at the same time you get the time elapsed.
The restart() method of an sf::Clock also returns the elapsed time so you can do this:
time = clock.restart();
elapsed = time.asSeconds();
or even:
elapsed = clock.restart().asSeconds();
Remember to remove your clock.restart(); from before the event loop.
Title: Re: Timebased movement not working..
Post by: TXRSTXN on February 08, 2016, 01:55:34 am
I moved restart() and it finally works! Thanks!

But how come? The loop goes round and round, why does it matter wether the restart is at the start or end of the loop? 
Title: Re: Timebased movement not working..
Post by: GraphicsWhale on February 08, 2016, 02:46:32 am
Imagine if you had a loop that looked like this:

while (!quit)
{
    //Do stuff

    clock.restart();
    float delta = clock.getElapsedTime().asSeconds();
}
 

The goal of delta is to measure the time it takes to complete //Do stuff. The clock gets reset to 0 and then you measure it. delta will always be 0 or near 0.

In order, you're basically doing:

- Do stuff
- Restart clock
- Take amount of time since the restart of the clock

Of course, in your code, you do poll events between the time you restart and the time you get the time elapsed, but your goal is to measure the entire game loop, not just the time it takes to poll events.

But if you rearranged it like this:

while (!quit)
{
    //Do stuff

    float delta = clock.getElapsedTime().asSeconds();
    clock.restart();
}
 

Now delta is the amount of time it took for whatever is in place of //Do stuff to occur. In order, you're now doing this:

- Restarting clock
- Doing stuff
- Taking amount of time since clock was restarted

As Hapax suggested, it may be easier to just do:

while (!quit)
{
    //Do stuff

    float delta = clock.restart().asSeconds();
}
 

Because sf::Clock::restart returns the time elapsed on the clock before it was restarted.

But as I mentioned earlier, you may want to do something like this:

const float timestep = 1.0f / 60.0f; //Update at 60hz
float accumulator = 0.0f;
while (!quit)
{
    accumulator += clock.restart().asSeconds();
    while (accumulator >= timestep)
    {
        accumulator -= timestep;

        //Do stuff
    }
}
 

And just move your circle at a fixed speed (100.0f/60.0f per update).

As for why you'd want to do this, look at:

http://gafferongames.com/game-physics/fix-your-timestep/ (http://gafferongames.com/game-physics/fix-your-timestep/)
http://gameprogrammingpatterns.com/game-loop.html (http://gameprogrammingpatterns.com/game-loop.html)