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

Author Topic: The right approach to movement and time. [SOLVED]  (Read 1170 times)

0 Members and 1 Guest are viewing this topic.

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
The right approach to movement and time. [SOLVED]
« on: June 14, 2020, 02:45:20 pm »
I'm making a simple shoot 'em up using SFML,applying what I'm learning from the "SFML Essentials" book,and in this book I learned that movement should be dependent on time rather than framerate,to insure a consistent experience across all different hardware.

Now,I have a general understanding of how both the Clock and Time classes work,but when it comes to applying them to enemy movement,I'm not sure exactly how to do that,and the book simply didn't linger on this issue long enough for me to understand,focusing more on animating sprites rather than moving them...

There are two was I thought of when it comes to approaching this,but I'm not sure of either of them:

1.I include all the move functions inside an if statement,so that the movement is only executed if the time elapsed between this frame and the one before it is above/below a certain threshold,but I don't know what the condition will be,as well as which unit of time to use:

sf::Time delta_time = clock.restart();

                /*Which one of these three do I use?*/
                float dt_elapsed = delta_time.asSeconds();
                float dt_elapsed = delta_time.asMilliseconds();
                float dt_elapsed = delta_time.asMicroseconds();

                if(/*What would be the condition here?*/){
                background.move(sf::Vector2f(0, 0.1 * dt_elapsed));
                enemy.move(sf::Vector2f(0, 0.15));
                }
 

This does work fine if I dt_seconds stores time in milliseconds,and the conditions is something like if (dt_elapsed >= 200) but the higher that number is the slower the movement becomes,and I don't know what the right value would be.

2.I multiply the chosen movement speed with the elapsed frame time,which is actually what's suggested in the book:

sf::Time delta_time = clock.restart();

                /*Which one of these three do I use?*/
                float dt_elapsed = delta_time.asSeconds();
                float dt_elapsed = delta_time.asMilliseconds();
                float dt_elapsed = delta_time.asMicroseconds();

               
                background.move(sf::Vector2f(0, 0.1 * dt_elapsed));
                enemy.move(sf::Vector2f(0, 0.15 * dt_elapsed));
 

Again,same problem,which unit of time do I use? Depending on whether I use seconds,milliseconds or microseconds the shape in question would either barely move or zoom across the screen (The book actually suggests I use seconds,but it doesn't linger over this specific issue for as long as I was hoping).
 
I could multiply the speed value with the elapsed time divided by a certain value x if I'm using millie/microseconds,or I could multiply the speed value directly with x,making it much bigger if I'm using seconds (We're talking values of somewhere between 150 and 200 instead 0.15 or 0.11,but is that well optimized?),but in each case I still don't know what x would be,and I don't want to just increase/decrease it until I get something that looks functional.

TL;DR How do I use the elapsed time between frames to obtain consistent movement speed across all different hardware,while making sure it's something well optimized?
« Last Edit: June 16, 2020, 10:20:55 pm by Riser »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10815
    • View Profile
    • development blog
    • Email
Re: The right approach to movement and time.
« Reply #1 on: June 15, 2020, 11:36:53 am »
There are different ways to achieve the goal of framerate independent movement.

The simplest and for a lot of cases sufficient approach for me is multiplying the delta-time with your movement calculation (your second approach).
In order to figure out the right units, you go back physics calculations: s = v * dt
And then replace the meter units with pixels or similar and you get [px] = [px/s] *

So something like this should do:
auto frame_time = clock.restart();
// ...
entity.move(velocity * frame_time.asSeconds());

Personally, I also recommend to use a normalized direction vector, that way you get the diagonal movement speed correct and can basically pick whatever direction you want.

entity.move(normalize(direction_vector) * velocity * frame_time.asSeconds());

Also once write a normalize function, not sure how efficent and precise it is, but it covers some edge cases.
(click to show/hide)

Now for more advanced games and certain micro stutter prevention, you'd use a fixed time step and do interpolation calculations.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: The right approach to movement and time.
« Reply #2 on: June 15, 2020, 09:31:22 pm »
To cover the question of which unit of time to use, use seconds.

And to cover the question of why seconds:
1) it's already a float so there's less chance of fractional information disappearing,
2) it's usually easier to understand the concept of speed when expressed in relation to seconds.
The second point is the main one really.

Basically, a x movement with a speed of 300 would move 300 units per second.

Of course, you're free to use any unit if you feel you have a specific reason to do so or want to be able to express speed in relation to a different unit of time but it's unlikely to be any better for you.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: The right approach to movement and time.
« Reply #3 on: June 16, 2020, 10:19:46 pm »
Alright,it works smoothly and with no issues now.

One of my concerns was that a large speed unit (200 or 300 like Hapax said) would be a bit too large (as opposed to the 0.2 or 0.3 I was previously using before worrying about time-related movement),but this appears to be no cause for concern.

As for the normalized direction vector and the normalize function,I'll start messing with those when the time comes for more advanced projects,right now I'm only working with basic,orthonormal movement.

Sincerely,thank you both.
« Last Edit: June 16, 2020, 10:27:33 pm by Riser »