Archived

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

Frame Rate Independent Animation

This topic is 5777 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 sprite

SPRITE sprite;

// used to calcualte time between frames

int oldTime = 0;

// set the sprite to change every 100 miliseconds

sprite.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.



Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Hello...
A few days ago, my dev team (err... me and the artist) where arguing exactly about this treat, if we should make the drawing of the scene independent or not. However, this it really worth the extra job, and will it look better? We are going for a side-scrooling like game, and I think that making it draw the screen once per game loop would be better, but he was saying that it should make things independent, like in quke3, for example (you will take 5 seconds to go from A to B, it doesen't mather if it's going at 80 fps or 6 fps). Now, I think that jumping frames on a 2d style game wouldn't look nice, but can anybody give a second opinion, or perhaps some advice?

Thanks a lot!!

Edited by - algumacoisaqualquer on February 21, 2002 9:30:32 PM

Share this post


Link to post
Share on other sites
An easy way to handle frame-rate independence is to forget about the idea of a "frame" in pretty much all of your code, and instead do your work simply based on time itself. I highly recommend using floating point for this, because it makes your life easier on many levels and you can drop things to integer granularity only when required.

The first step is to have a timing function that can provide for you the time that''s elapsed since your application began. You can create this as a wrapper around any lower-level timing function(s) you like, although GetTickCount() may not be the best choice (QueryPerformanceCounter() with QueryPerformanceFrequency() are far more preferable). At some point this might boil down to a function like this:

// return floating-point time in seconds since application start
float TIME_GetTimeSeconds();

From here, you simply record this time once per frame, along with the time at the previous frame, from which you can compute a delta time for the frame. For example, when you''re running at 50 FPS, the delta time would be 0.02, and if you were running at 10 FPS it''d be 0.1, etc. Keep this delta time accessible to any functions that would be time-dependent.

For animation, advancing your floating-point frame based on this value is a simple one-line computation:

currentAnimFrame += deltaTime * animFramesPerSecond;

In other words, if your animation runs at 30 FPS, and your deltaTime is 0.1 (i.e. your game is running at 10 FPS), then your current animation frame will advance by 3.0. Likewise, if your deltaTime is 0.02 (i.e. your game is running at 50 FPS), then your animation frame will advance by 0.6.

So your floating-point current animation frame will advance consistantly regardless of your game''s frame rate. If you''re in a 2D sprite environment, you can choose the sprite frame at rendering time based on an integer truncation or rounding of this floating-point frame. If you''re in a 3D environment, you can use the integer part of the current frame to determine two frames of animation data to fetch, and then use the fractional part to interpolate smoothly between the two.

The whole process is relatively simple overall, and the internal logic of your game moves at the same speed regardless of how fast it can be displayed.

- Chris

Share this post


Link to post
Share on other sites