12
\$\begingroup\$

I've read two other threads here on movement: Time based movement Vs Frame rate based movement?, and When should I use a fixed or variable time step?

but I think I'm lacking a basic understanding of frame independent movement because I don't understand what either of those threads are talking about.

I'm following along with lazyfoo's SDL tutorials and came upon the frame independent lesson. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

I'm not sure what the movement part of the code is trying to say but I think it's this (please correct me if I'm wrong): In order to have frame independent movement, we need to find out how far an object (ex. sprite) moves within a certain time frame, for example 1 second. If the dot moves at 200 pixels per second, then I need to calculate how much it moves within that second by multiplying 200 pps by 1/1000 of a second.

Is that right? The lesson says:

"velocity in pixels per second * time since last frame in seconds. So if the program runs at 200 frames per second: 200 pps * 1/200 seconds = 1 pixel"

But...I thought we were multiplying 200 pps by 1/1000th of a second. What is this business with frames per second?

I'd appreciate if someone could give me a little bit more detailed explanation as to how frame independent movement works.

Thank you.

ADDITION:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

That's code that moves a dot down the screen. I think I have everything correct so far. It moves down the screen but there is a bit of an odd thing that happens that I can't explain. The dot is supposed to stay at the y=580 when it gets to greater than that y-value. However, every time I run the program, the dot will end up in a different location, meaning a little bit to a lot more than 580, so the dot is halfway or more than halfway off the screen (the dot is 20 pixels, screen dimensions 800x600). If I do something like click and hold the title-bar of the program, and then release, the dot disappears off the screen. How come it's variable each time? As for the titlebar problem I think it's because when I hold on to the titlebar, the timer is still running, and the time elapsed gets larger, resulting in a larger distance the dot moves in the next frame. Is that right?

\$\endgroup\$
1
  • \$\begingroup\$ Your addition is actually another question. You should make it a second question instead of adding it to your existing one. It can be answered easily though: Just calculate the y-movement, eg. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f); then do: if(y + yMovement <= 580){ y += yMovement; } else { y = 580; } \$\endgroup\$
    – bummzack
    Commented Mar 9, 2011 at 15:40

3 Answers 3

11
\$\begingroup\$

NOTE: All fractions are meant to be floats.

Frame independent movement works by basing movement off of time. You get the amount of time that is spend since the last frame (so if there are 60 frames in one second, each frame takes 1.0/60.0 seconds, if all the frames took the same amount of time) and find out how much movement that translates into.

If you want your entity to move a certain amount of space for a specified unit of time (we will say 100 pixels for every second of time) then you can find out how many pixels you should move per frame by multiplying the amount of movement per second (100 pixels) by the amount of time passed in seconds (1.0/60.0) in order to figure out how much movement should take place in the current frame.

It works by figuring out how much movement you should perform per frame by using the amount of time elapsed and a speed that is defined with some unit of time (seconds or milliseconds are preferable). So your calculation might look like: movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

I hope that made some kind of sense to you.

I want to move my guy 200 pixels to the right every second. If the current frame is run 50 milliseconds after the previous frame, then I should move my guy a fraction of the speed previously specified (which was 200 pixels). I should move him 50/1000th of the distance because only a 1/20th (50/1000 = 1/20) of time has passed. Therefore it would make sense to only move him 10 pixels (if 19 more frames occurred, 50 milliseconds apart from each other, then the total amount of movement in that second would be 200 pixels, the amount we wanted).

The way frame independent movement works is that frames usually occur at variable time steps (there is a different amount of time that takes place between subsequent frames). If we constantly move an entity a constant distance every frame, then the movement is based on the frame rate. If there is a lot of time between frames, the game will seem to move too slow and if there is not a lot of time between frames, the game will seem to be going to fast. (too little time between frames = a lot of frames = more movement) To overcome this, we use a speed in terms of time and keep track of the time between frames. That way we know how long it's been since we last updated the position and how much further we should move the entity. By using time we can eliminate the dependence on the frame rate and our game will look more or less the same on different frame rates.

Frames per second : This is the amount of frames that take place per second. Usually a frame rate is either how many times the game is drawn/rendered a second or how many times the game loop is completed a second.

Fixed Verse Variable Time Step : This refers to the amount of time between frames. Usually, the time between frames will not be constant. Certain systems/cores like physics will need some unit of time in order to simulate/run something. Usually, physics systems are more stable/scalable if the time step is fixed. The difference between fixed/variable time steps are in the names. Fixed time steps are what they sound like: time steps that occur at a fixed rate of time. Variable time steps are time steps that occur at varying/different rates of time.

\$\endgroup\$
10
  • \$\begingroup\$ In the example you give, 50 milliseconds is the time for each frame, correct? And that was calculated by 1000/FPS? And so the movement you need to make each frame is pixels per second * 50/1000? \$\endgroup\$ Commented Mar 9, 2011 at 4:24
  • \$\begingroup\$ hm, I realized though that the milliseconds for each time frame would probably be variable, wouldn't it? Something like getTicks()-startTicks would always be different and not constant. \$\endgroup\$ Commented Mar 9, 2011 at 5:20
  • \$\begingroup\$ @Omnion: If you specify distance in "pixels per second" you can't use milliseconds... it should be 1.0/60.0 not 1000/60 which would result in something entirely different. \$\endgroup\$
    – bummzack
    Commented Mar 9, 2011 at 7:36
  • \$\begingroup\$ @ShrimpCrackers yes, the elapsed time changes. Imagine an older PC that isn't capable of rendering 60 fps. You still want the game to run at the same speed (but not the same fps) on such a machine. \$\endgroup\$
    – bummzack
    Commented Mar 9, 2011 at 7:48
  • \$\begingroup\$ so, then in the lazyfoo tutorial, what does the 1000 mean in deltaticks/1000.f? FPS? 1000 milliseconds? I'm a bit confused right now. It seems that FPS is necessary in determining the time required for each frame, but that it doesn't actually calculate into the movement. \$\endgroup\$ Commented Mar 9, 2011 at 8:15
7
\$\begingroup\$

In frame dynamics your code for (for instance) moving an entity would look like this:

x = x + speedPerFrame

If you want to be frame-independent, it could look like this:

x = x + speedPerSecond * secondsElapsedSinceLastFrame
\$\endgroup\$
1
  • \$\begingroup\$ thanks, that makes sense. I have an another question above. \$\endgroup\$ Commented Mar 9, 2011 at 15:35
1
\$\begingroup\$

Regarding the additional question.

Your point stops at different locations each time because you don't check for the boundary (y > 580) when you move it. You only stop updating it further once its past 580.

On the last frame before you cross 580 you could be starting from 579 or you could be at 570 or you could be at 100. You also could be stepping 1 pixel forward or 1000, depending on how long the last frame took to execute.

Just change your IF condition to something like this and you should be fine.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .