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

Author Topic: Updating positions based on delta time  (Read 5784 times)

0 Members and 1 Guest are viewing this topic.

PixelMuffin

  • Newbie
  • *
  • Posts: 18
    • View Profile
Updating positions based on delta time
« on: July 06, 2012, 03:17:06 am »
Hi.

I just found out about SFML and have been developing games for a few years now. I absolutely love the API. One question however is regarding the apparent ability for SFML to handle most of the timing and updating groundwork. I am writing a simple pong clone all in one file in case I had trouble and am finding some oddities in the updating of the paddle locations. Here is the source for my main loop. I do enable vertical sync in the initialization phase.

 
  // Start the game loop
    while (window.isOpen())
    {    
        // Restart the clock and get the delta time
        time = clock.restart();
        float dt = time.asSeconds();
       
        // Poll for events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed)
                window.close();
           
            // Escape pressed : exit
            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                window.close();
           
            // Check for user input
            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Down)
                player1.y += 10 * dt;

           
            // Check for user input
            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Up)
                player1.y -= 10 * dt;
        }
   
        // Update the object positions
        paddle1.setPosition(player1.x, player1.y);
        paddle2.setPosition(player2.x, player2.y);
           
        // Clear screen
        window.clear();
           
        // Draw the sprites
        window.draw(background);
        window.draw(paddle1);
        window.draw(paddle2);
        window.draw(ball);
        window.draw(text);
       
        // Update the window
        window.display();
    }

 

It compiles fine but the paddle moves way too slowly. I tried multiplying the number by 1000, to where is got to a reasonable speed but it was jerky and not smooth. Has anyone dealt with this? I don't really need a super accurate fixed timestep loop. I should also add that my player1 and 2 are structs with a simple x and y float.

Thank you.

victorlevasseur

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: Updating positions based on delta time
« Reply #1 on: July 06, 2012, 08:58:10 am »
Hello,
I'm not sure, but maybe it's better to restart and get the values of the timers after the event management.
You can also use milliseconds instead of asSecond because it's more accurate.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10159
    • View Profile
    • development blog
    • Email
Re: Updating positions based on delta time
« Reply #2 on: July 06, 2012, 11:35:35 am »
It's a perfectly normal calculation that makes your paddles move so slowly. If you got a fix framerate due to VSync (= 60fps) you'd get 0.016 for dt, thus:
10px/s * 0.016s = 0.16px
So your paddle moves 0.16px per frame, which isn't that fast.

Also I'd suggest to use the class sf::Keyboard with its function isKeyPressed() instead of working with events, because evens get triggered only so often and at the beginning there's a repeate delay.
        // Check for user input
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            player1.y += 40 * dt;

           
        // Check for user input
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            player1.y -= 40 * dt;
Also keep in mind with the current update code, your dt doesn't take in account the time spend on the event handling or the position setting. So you should put it just before the draw statements.
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/

PixelMuffin

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Updating positions based on delta time
« Reply #3 on: July 06, 2012, 12:04:04 pm »
Okay, so if I am doing this incorrectly, do either of you have a main loop I can take a peak at. The problem with my loop is that delta time is either too small or updates too infrequently that the movement is choppy.

I changed the keyboard input method and there was no change. So it seems my main loop is being updated with a weird delta time. Any idea how to fix it to be more smooth?

Any other ideas?
« Last Edit: July 06, 2012, 12:25:42 pm by PixelMuffin »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10159
    • View Profile
    • development blog
    • Email
Re: Updating positions based on delta time
« Reply #4 on: July 06, 2012, 02:15:01 pm »
I changed the keyboard input method and there was no change. So it seems my main loop is being updated with a weird delta time. Any idea how to fix it to be more smooth?
I hope you only relate this to the smoothness and not to the low speed (otherwise you'd have completly ignored the first part of my previous answer...). ;)

You hopefully took it out of the event loop, right?
I've taken your code and implemented a quick test case and it works fine, no choppy movements:
#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Test" );
        window.setVerticalSyncEnabled( true );

        sf::Vector2f player1(10, 10);
        sf::Vector2f player2(590, 10);
        sf::RectangleShape paddle1(sf::Vector2f(10, 30));
        sf::RectangleShape paddle2(sf::Vector2f(10, 30));

        sf::Clock clock;
        sf::Time time;

        float dt = 0;
        const int speed = 100;

        // Start the game loop
        while (window.isOpen())
        {      
               
                // Poll for events
                sf::Event event;
                while (window.pollEvent(event))
                {
                        // Close window : exit
                        if (event.type == sf::Event::Closed)
                                window.close();
                       
                        // Escape pressed : exit
                        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                                window.close();
                }
               
                       
                // Check for user input
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                        player1.y += speed * dt;

                       
                // Check for user input
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                        player1.y -= speed * dt;
       
               
                // Restart the clock and get the delta time
                time = clock.restart();
                dt = time.asSeconds();


                // Update the object positions
                paddle1.setPosition(player1.x, player1.y);
                paddle2.setPosition(player2.x, player2.y);
                       
                // Clear screen
                window.clear();
                       
                // Draw the sprites
                window.draw(paddle1);
                window.draw(paddle2);
               
                // Update the window
                window.display();
        }

        return EXIT_SUCCESS;
}

Also if you think the delta time is too small, then you should either work with a fixed timestep, or only updated it every second (or half a second).
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/

PixelMuffin

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Updating positions based on delta time
« Reply #5 on: July 06, 2012, 09:28:58 pm »
I changed the keyboard input method and there was no change. So it seems my main loop is being updated with a weird delta time. Any idea how to fix it to be more smooth?
I hope you only relate this to the smoothness and not to the low speed (otherwise you'd have completly ignored the first part of my previous answer...). ;)

You hopefully took it out of the event loop, right?
I've taken your code and implemented a quick test case and it works fine, no choppy movements:
#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Test" );
        window.setVerticalSyncEnabled( true );

        sf::Vector2f player1(10, 10);
        sf::Vector2f player2(590, 10);
        sf::RectangleShape paddle1(sf::Vector2f(10, 30));
        sf::RectangleShape paddle2(sf::Vector2f(10, 30));

        sf::Clock clock;
        sf::Time time;

        float dt = 0;
        const int speed = 100;

        // Start the game loop
        while (window.isOpen())
        {      
               
                // Poll for events
                sf::Event event;
                while (window.pollEvent(event))
                {
                        // Close window : exit
                        if (event.type == sf::Event::Closed)
                                window.close();
                       
                        // Escape pressed : exit
                        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                                window.close();
                }
               
                       
                // Check for user input
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                        player1.y += speed * dt;

                       
                // Check for user input
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                        player1.y -= speed * dt;
       
               
                // Restart the clock and get the delta time
                time = clock.restart();
                dt = time.asSeconds();


                // Update the object positions
                paddle1.setPosition(player1.x, player1.y);
                paddle2.setPosition(player2.x, player2.y);
                       
                // Clear screen
                window.clear();
                       
                // Draw the sprites
                window.draw(paddle1);
                window.draw(paddle2);
               
                // Update the window
                window.display();
        }

        return EXIT_SUCCESS;
}

Also if you think the delta time is too small, then you should either work with a fixed timestep, or only updated it every second (or half a second).

Very very bizarre. I modified your loop and it worked perfectly. Still not sure what the case was in my code. And was there really a necessity to move the delta update? Wouldn't it make sense to get the delta time before the update rather than after.

Thank you again! :D

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10159
    • View Profile
    • development blog
    • Email
Re: Updating positions based on delta time
« Reply #6 on: July 07, 2012, 12:21:23 am »
Very very bizarre. I modified your loop and it worked perfectly. Still not sure what the case was in my code.
I bet you've just changed the if conditions of the old code, thus the key checking was still inside the event loop (while(window.isOpe())). With that setup the paddle will only get moved if an event has occured and since pressing a key always invokes an event you get about the exacte same result.

And was there really a necessity to move the delta update? Wouldn't it make sense to get the delta time before the update rather than after.
This is something that every so often starts to confuse me, but in the end it doesn't really matter where you put it. Diffrent placings only change the pasted time. For example if you put it directly infront of the update code, the dt will contain the time for the update and the drawing of the last frame plus the event handling of the current frame. If you put it after the update code it contains the drawing time of the last frame plus the event and update time of the current frame. If you put it at the end or the beginning of the main loop it sums up the event & update & draw time of the last frame.
This means you can choose whatever fits best; most of the time one just wants the last frametime thus it would complelty okay to have it at the beginning, as you had it. (Sorry my bad...) ;D
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/