Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Timebased movement not working..  (Read 2935 times)

0 Members and 1 Guest are viewing this topic.

TXRSTXN

  • Newbie
  • *
  • Posts: 6
    • View Profile
Timebased movement not working..
« 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;
}

 

GraphicsWhale

  • Full Member
  • ***
  • Posts: 131
    • View Profile
Re: Timebased movement not working..
« Reply #1 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.
« Last Edit: February 07, 2016, 11:38:27 pm by GraphicsWhale »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Timebased movement not working..
« Reply #2 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.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

TXRSTXN

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Timebased movement not working..
« Reply #3 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? 

GraphicsWhale

  • Full Member
  • ***
  • Posts: 131
    • View Profile
Re: Timebased movement not working..
« Reply #4 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://gameprogrammingpatterns.com/game-loop.html
« Last Edit: February 08, 2016, 02:51:43 am by GraphicsWhale »

 

anything