Archived

This topic is now archived and is closed to further replies.

Specchum

SDL_GetTicks and frame independent movement - how?

Recommended Posts

I''d like to have frame independent movement in my 2-d game being coded using SDL. I know that I should be using SDL_GetTicks to calculate the frames per second. In fact I have done that and I have the value for frames per second and everything, but erm... how do I tie this in with movement along x and y axis? "There is no dark side of the moon." - Pink Floyd

Share this post


Link to post
Share on other sites
Say you want to move 50 pixels per second, and have 50 FPS. So how many pixels per frame you have to move?

Usually you save the last update time, and on the next update you calculate the delta time.
Say you want to have a speed of 30 pixels per second, so you multiply those 30 with your delta-time, resulting to a frame independent movement. (Make sure you don''t use integers as you probably will end up with non integer movement rates)

Share this post


Link to post
Share on other sites
You mean something like this:

time = SDL_GetTicks()

some lines of code....

time_diff = SDL_GetTicks() - time

time = SDL_GetTicks()

hero.x = hero.x + (30 * time_diff)

where hero.x is the movement of the hero along x axis.

so, frames per second isn''t required for computation in this case?

"There is no dark side of the moon." - Pink Floyd

Share this post


Link to post
Share on other sites
Thats right, simple physics tells us...

Distance = Speed x Time

Therefore the amount you move your character should be the desired speed multiplied by the time since the last update.

Share this post


Link to post
Share on other sites
usually you will do:

actualTime = getTime();
hero.x += (30 * (lastUpdate - actualTime));
...
lastUpdate = actualTime;
return;


so this will make your hero walk 30 pixels per second.

Share this post


Link to post
Share on other sites
Your probably factoring in the time wrong. Draw a square on the screen that changes colors every second, if it is blinking too fast, then you''ve found the problem.

Share this post


Link to post
Share on other sites
Note that functions like SDL_GetTicks returns the time in millseconds since SDL was initialized, so if you want to calculate the velocity in terms of units moved per second, you''ll have to divide this value by 1000.


Uint32 timeMS = SDL_GetTicks();
Uint32 oldTimeMS;
Uint32 frameTimeMS;
float frameTime;

while (gameIsRunning)
{
oldTimeMS = timeMS;
timeMS = SDL_GetTicks();
frameTimeMS = timeMS - oldTimeMS;
frameTime = (float)timeMS / 1000.0f;

// to use this to calculate speed is the same
position += velocity * frameTime;
}

Share this post


Link to post
Share on other sites
Thanks for the replies guys! I''m off to check it out!

Zaddras, post your code if you wish for help! Shooting in the dark isn''t going to help!

"There is no dark side of the moon." - Pink Floyd

Share this post


Link to post
Share on other sites

now=SDL_GetTicks()/1000.0f;
diff=last-now;
//get input, draw, etc...

last=now;

and the mooving function:

void Moving(int xp, int yp) {



if (direction==UP) {
if ((ypos-2)<56) {
turbing=false;
}
else {
turbing=true;
ypos-=(2*diff);
}
}
else if (direction==DOWN) {
if ((ypos+2)>565) {
turbing=false;
}
else {
turbing=true;
ypos+=(2*diff);
}
}
else if (direction==LEFT) {
if ((xpos-2)<0) {
turbing=false;
}
else {
turbing=true;
xpos-=(2*diff);
}
}
else if (direction==RIGHT) {

if ((xpos+2)>765) {
turbing=false;
}

else {
turbing=true;
xpos+=(2*diff);
}



}
}


[edited by - ZadrraS on April 22, 2004 7:38:57 AM]

Share this post


Link to post
Share on other sites
now=SDL_GetTicks()/1000.0f;
diff=last-now;
//get input, draw, etc...
last=now;

this is wrong... you should not take the time at the begining of your main loop AND at the end... this is wrong because your OS might decide to take over sometime during the middle of the app, and that last wont be correctly in- sync. (i might have worded that wrong, dont quote me on it).

the proper way would be to do this:



//main game loop

while(!gameover)
{
PreviousTime = CurrentTime; //start the counter for FPS


CurrentTime = SDL_GetTicks(); //end the counter for FPS


FrameTime = (CurrentTime - PreviousTime) * 0.001f; //find the time elapsed in milliseconds and convert it to seconds by multiplying by .001


//NOW do your whole game loop here!




do you see how this works? immediately in the begining of the loop we take the previous time, then right after we get the current time, then right after that we subtract the second one from the first. the first time this loop runs, there will probably be no difference in the 2 (obviously you would have to initialize current_time). but, when the loop goes around one time, it will get to previous time and assign that value to current_time (which would have happend an entire game loop ago), then current time is assigned the time. the subtracted amount is how much time passed during the game loop. now since each lines of code are right next to each other, the OS wont hog you and screw you over.



now, on to your movement code, yours looked ok but it seemed like you were incrementing it by a low number maybe?




if (direction==UP)
{
if ((ypos-2)<56)
{
turbing=false;
}
else
{
turbing=true;
ypos = yPos + (500 * FrameTime);
}
}


obviously i hard-coded 500. but you can play around with that value to get the speeds you want. hope i helped.



[edited by - graveyard filla on April 25, 2004 1:23:55 PM]

[edited by - graveyard filla on April 25, 2004 1:40:08 PM]

[edited by - graveyard filla on April 25, 2004 1:40:47 PM]

Share this post


Link to post
Share on other sites
Thanks gf, its not, nor the second time you help me . But whats the diffrence between this:
ypos = yPos + (500 * FrameTime);
and this:
ypos+=(30*diff);
i don''t see a diff...

Share this post


Link to post
Share on other sites
hmmm, doesn''t work too framerate independant, it goes much faster up or left than down or right... Whats wrong?

void Moving(int xp, int yp) {



if (direction==UP) {
if (((ypos-2)<56) || (map[((yp-3)-56)/32][xp/32]!=OPEN) || (map[((yp-3)-56)/32][(xp/32)+1]!=OPEN)) {
direction=STOP;
turbing=false;
}

else {
turbing=true;
ypos+=(80*diff);
}
}
else if (direction==DOWN) {
if (((ypos+2)>565) || (map[(((yp+4)-56)/32)+1][xp/32]!=OPEN) || (map[(((yp+4)-56)/32)+1][(xp/32)+1]!=OPEN)) {

direction=STOP;
turbing=false;

}
else {
turbing=true;
ypos-=(80*diff);
}
}
else if (direction==LEFT) {
if (((xpos-2)<0) || (map[(yp-56)/32][(xp-3)/32]!=OPEN) || (map[((yp-56)/32)+1][(xp-3)/32]!=OPEN)) {

direction=STOP;
turbing=false;

}
else {
turbing=true;
xpos+=(80*diff);
}
}
else if (direction==RIGHT) {
if (((xpos+2)>765) || (map[(yp-56)/32][((xp+3)/32)+1]!=OPEN) || (map[((yp-56)/32)+1][((xp+3)/32)+1]!=OPEN)) {

direction=STOP;

turbing=false;

}
else {
turbing=true;
xpos-= (80*diff);
}



}
}

Don''y look at the assy collision detection

Share this post


Link to post
Share on other sites
No, this is stupid. Ive been trying to figure out whats wrong with my code, but i don''t get it. Why my time based movement isn''t time based???

Share this post


Link to post
Share on other sites
Get how many miliseconds it takes to process one frame (call it ''t'')
Use a point of reference, i.e 1 pixel/second. ( call it ''60'' )
Move your object by the ratio.

Since 1 second == 1000 miliseconds...

object.x += OBJECT_SPEED * t/1000 * 60;

Example:
if t = 20 (fps = 50):
object.x += OBJECT_SPEED * 20/1000 * 60;
object.x += OBJECT_SPEED * 1.2; // object moves a little bit faster

if t = 10 (fps = 100):
object.x += OBJECT_SPEED * 10/1000 * 60;
object.x += OBJECT_SPEED * 0.6; // object moves a little bit slower

if t = 16.6667 (fps = 60):
object.x += OBJECT_SPEED * 16.6667/1000 * 60;
object.x += OBJECT_SPEED * 1; // object moves at exact speed.

Yay!

Share this post


Link to post
Share on other sites
I didn''t fully understand what you ment, and i didn''t really understand how would it solwe the problem... More explaining?

Share this post


Link to post
Share on other sites
For example, you want your objects to move 60 pixels in one second (forget what I said 1 pixel/second, I was wrong). Then you decide at what fps your game will run at 'normal' speed. Let's say you pick 60. At 60 fps, your objects will move exactly 1 pixel each frame, right? 1 pixel/frame, 60 frames/second, 60 pixels/second.

So, at 60 fps, your game would run at 'normal' speed. Now, what if for some reasons the fps drops down to 1 fps, you want your objects to move 60 pixels on each frame now, right? Since your game only processes 1 frame in 1 second, and you have set the standard that your objects will move 60 pixels in 1 second, you want to move your object 60 pixels on that frame because it takes 1 second to process that frame. And the code I show you does that.

object.x += OBJECT_SPEED * time_elapsed/1000 * 60;

why dividing it by 1000? Because there are 1000 miliseconds in 1 second. Why multiplying with 60? Because you set it that way. If you want it 100, that's fine too. That means your game will run at 'normal' speed when fps reaches 100. Or:

object.x += OBJECT_SPEED * time_elapsed * 60/1000;

Maybe much better. 60 pixels/second == 60 pixels/1000 miliseconds.

[edited by - alnite on April 26, 2004 3:13:42 PM]

Share this post


Link to post
Share on other sites
Wait a sec, isn''t that the same thing i do? Time diffrence between last and this frame * the speed i want an object to go a sec.

Share this post


Link to post
Share on other sites
quote:
Original post by ZadrraS
Wait a sec, isn't that the same thing i do? Time diffrence between last and this frame * the speed i want an object to go a sec.
If the time difference is 20 miliseconds, for example, and the speed/second the object is moving is 100 pixels/second. You will move at 20 * 100 = 2000 pixels!

There is a clash of units being measured here. 20 miliseconds * 100 pixels/1 second . milisecond vs second !?!? So you need to divide it by 1000.

20 miliseconds * 100 pixels / 1000 miliseconds = 2 pixels.

[edited by - alnite on April 26, 2004 3:28:44 PM]

Share this post


Link to post
Share on other sites
hey zad, if you cant get this to work, then its not a big deal if you dont have frame-rate independant movement. all you have to do is lock your game at 30 FPS or whatever you want. this will be fine for most situations and i dont plan on using frame-rate independant movement for the RPG im developing because its a lot of extra hassle. although my pong clone used it, even then there was side- problems that wouldnt have happend if i didnt use it.

Share this post


Link to post
Share on other sites
Emmm. ok.... so i already did exactly as you do. just read the post before posting. my time diffrence is already divided by 1000, so i don''t need to do it again. Theres another problem.
(And thanks for the linkie, ill have a look)

Share this post


Link to post
Share on other sites