-
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;
}
-
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.
-
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.
-
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?
-
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)