Frame Rate Independent Animation

Started by
11 comments, last by grasshopa55 22 years, 2 months ago
Quick Question, I have a sprite, and I want to animate him at say, 30 fps. Since every system will perfom differently, and I don''t want to lock the frame rate, how would I go about calculating the delay time on the animation? Would you use a technique similar to the one used for movement? movementVal = desireddistance * secondsperframe If so, would you need to calculate the delay every frame? ----------------------------- kevin@mayday-anime.com http://games.mayday-anime.com
-----------------------------kevin@mayday-anime.comhttp://www.mayday-anime.com
Advertisement
Well, it isn''t very complicated.
You need to create a timer which is used to calculate picture position/shape/...
Your drawing function will just get the calculated values and draw the new screen.
cYaDjR====================may you be in heaven half an hourbefore devil knows you''re dead ;)
I don't really understand what you mean. It sounds like the answer to the frame rate independent movement problem. I'm refering to sprite animation. Since sprites may have 10 to 12 frames of animation, in order for the animation to look smooth, the frames need to be updated a specific rate. If you let the sprite animate as fast as possible, sometimes the animation is too fast to see. To fix that, a delay is used. An example is that you want your main character's walking animation to be displayed at 30 frames per second. Say you are getting 60 fps overall, then your character would only update to the next frame every 5 ms.

Now say you don't want to lock the fps, but you still want the character to animate at 30fps. How do you do determine the delay? This is my real question.

-----------------------------
kevin@mayday-anime.com
http://games.mayday-anime.com

Edited by - grasshopa55 on February 21, 2002 1:10:40 PM
-----------------------------kevin@mayday-anime.comhttp://www.mayday-anime.com
Can''t you just take the desired fps and find out how many milliseconds that comes out to per frame, and then every time that interval of time passes, increment the sprite''s frame counter, making sure to do it with a while () or something in case you have to catch up.

Example: 30 fps desired target animation rate = 1000/30 = 33 ms per frame.

In your game loop, check to see if time elapsed since last cycle is >=33. If not, skip animation on this sprite. If so:

while (elapsed_time>=33)
{
sprite.frame++;
elapsed_time-=33;
}

Would this work?

Chris
Florida, USA
RTS Engine in Development
http://www.knology.net/~heaven/rts.htm
Florida, USA
Current Project
Jesus is LORD!
Or you could simply timestamp the animation (using GetTickCount or similar) when it starts, then whenever you want to draw the sprite just get the delta time (GetTickCount()-StartTime), and determine which frame matches that delta.

For instance:
The sprite has 12 frames (frame 0 to 11) and should be animated at 10fps (the frame displayed should change every 100ms). If DeltaTime is 4000 (4 seconds have passed since the animation loop started) then
DisplayFrame = (DeltaTime div 100) mod 12;
so
DisplayFrame = (4000 div 100) mod 12;
DisplayFrame = 4

This prevents the inaccuracy in the timer from building up over time (the timer is likely +/-5ms the actual time)



Edited by - Michalson on February 21, 2002 2:17:21 PM
This is how you can do it. Lets say you want your sprite to move 10 pixels in 2 seconds (or 2000 miliseconds). Ill refer to the 10 pixels as "distance" and the 2 seconds as "end time".

Use a timer and get a time when your program first starts (outside of your main game loop). A good timer for this is GetTickCount()). Store that in a value (ie: int oldTime). Lets just say it returned 100,000 miliseconds since Windows has started.

Now in your main game loop get the time for each frame. Store this in a value as well (ie: int newTime). Lets say that returned 100,050 miliseconds.

Now you want to take newTime - oldTime to get the amount of miliseconds that has passed between the two frames. This would equal 50 miliseconds. Now we know the sprite will move every 50 miliseconds.

But how many times will it move before 2 seconds has passed (or the end time)?. We can represent this with the formula "x * 50 = end time". "x" is the number of times the sprite will move before the end time is reached. Using simple algebra you can make the formula "x = end time / 50" or "x = end time / (newTime - oldTime)". Remember we got 50 miliseconds from finding the amount of miliseconds between two frames. The answer should give you 40 times that the sprite will move.

So now we got the formula "end time/(oldTime - newTime)" which gives you the number of times the sprite will move (I''ll refer to this as the sprite''s "moves"). Now we got to figure out how many pixels it will go for each frame. We know that it will move a certain amount 40 times to reach the distance (which is 10 pixels).

So now we got the formula x * 40 = 10. Simple algebra makes the formula x = 10/40 or x = distance / moves. Make the calculations and you get 0.25 pixels the sprite has to move per frame to reach 10 pixels in 2 seconds.

I don''t know how your storing your variables, but lets say you have a struct with the varialbes x and y. Just make your x a float or a double (if your using C/C++) and do "x += distance / (end time/(oldTime - newTime)" for each frame.

Now you have a method that keeps your game moving the same speed on everyone''s computer. And the best part is it doesn''t lock the framerate . So someone with a 2.0ghz Pentium 4 will get 300fps while someone with a 233mhz Pentium 2 will get 30 fps. However, your sprite will still move 10 pixels in 2 seconds on both machines. It''s just that the faster one will be the smoother and the slower one will be choppier. It sure beats slowdown though . Now you know how the proffesionals do it.

If you have any more questions just reply to this thread becuase it''s good to have the information on the message board. That way if anybody else is having the same problem they can search the message board and find this thread.
Thanks Sassy, but that's the answer to frame independent move question . I was trying to figure out how to build a frame independent animation technique. Try to think about it in terms of old 2D frame animation.

Edited by - grasshopa55 on February 21, 2002 3:43:13 PM
-----------------------------kevin@mayday-anime.comhttp://www.mayday-anime.com
Frame Rate Independent? Why not Time Independent? Blaah
Whoops. I just realized I didn''t answer your question. Your question is even easier.

Lets say you want to go to the next frame of your animation every 100 miliseconds. Just keep a counter with your sprite that adds up the amount of time that passes between each frame (use the value from "newTime - oldTime"). When the counter is over 100 miliseconds go to the next frame.

here''s how it could look. We''ll assume that sprite is a struct that countains all of it''s info including the counter.

  // declaring the spriteSPRITE sprite;// used to calcualte time between framesint oldTime = 0;// set the sprite to change every 100 milisecondssprite.counterMax = 100;void Animate(int change){   // add to the amount of miliseconds that has passed since the   // last update to the sprite   sprite.counter += change;   // if the time that has passed since the last update is past    // the total time before an update...   while(sprite.counter >= sprite.counterMax)   {      sprite.counter -= sprite.counterMax;      // move to the next frame      sprite.frame++;   }}void InitGame(){   oldTime = GetTickCount();}//--------You main game loop ------------//void MainGame(){   while(1)   {      int newTime = GetTickCount();         int change = newTime - oldTime;      oldTime = newTime;      Animate(change);      DrawSprite();   }}  


So lets say that when the while loop is hit the counter equals 134 miliseconds. First we subtract 100 from the counter which gives us 34 miliseconds. Remeber that we want to update every 100 miliseconds and not every 134 miliseconds. Now we move to the next frame.

The reason why I used a while loop is simple. Lets say that a user has a really slow computer. You want to update every 100 miliseconds. His computer has 215 miliseconds each frame. If it was an if statement, the block of code would run once and then it would exit the function. It would subtract 100 from 215 leaving the counter at 115.

The counter is still above 100 miliseconds which means that the sprite should have moved updated twice between frames. Since it''s a while loop it will see that the counter is still greater than 100 and will update the sprite again.

I hope that wasn''t too confusing. If you don''t understand something just ask me to explain it better.



Thanks. That was pretty much the answer I thought of. I was having an issue trying to test my application on more than one machine. My main machine has a GeForce2 MX 64MB and on average I was getting an extremely high framerate, and my characters were animating very fast. I will implement this along with the movement logic. Thanks again.

-----------------------------
kevin@mayday-anime.com
http://games.mayday-anime.com
-----------------------------kevin@mayday-anime.comhttp://www.mayday-anime.com

This topic is closed to new replies.

Advertisement