Jump to content
  • Advertisement
Sign in to follow this  
Fujitaka

Animation Speed help.

This topic is 3267 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

I have been working on some animation code in SDL and C, but I am stuck on what to use for calculating the animation's speed. What I use is a bmp 192x128. Width of each frame is 32. Hight is 48; I though about using one of these: int SDL_AddTimer(interval, callback, param) Add a new timer to the pool of timers already running. SDL_Delay(ms) Wait a specified number of milliseconds before returning. int SDL_GetTicks() Get the number of milliseconds since the SDL library initialization. SDL_RemoveTimer(t) Remove one of the multiple timers knowing its ID. SDL_SetTimer(interval, callback) Set a callback to run after the specified number of milliseconds has elapsed. but not sure the proper way to calculate the speed of the animation. Hopefully someone in here can help me with that. Here is the code I have so far. Atm all it does is play the animation over and over really fast.
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>


SDL_Surface *screen;

// Draw Background.
startanim(char* string, int firstframe, int lastframe)
{

SDL_Surface *bkg; 
SDL_Rect src, dest;
int animx;

 bkg = IMG_Load(string);
 if (bkg == NULL) {
 printf("Unable to load sprite.\n");
 return 1;
}


 
for (animx=firstframe; animx <= lastframe; animx++) {
src.x = animx * 32;
src.y = 0;
src.w = 32;
src.h = 48;
dest.x = 0;
dest.y = 0;
dest.w = 32;
dest.h = 48;
SDL_BlitSurface(bkg, &src, screen, &dest);
SDL_Flip(screen);
}
SDL_FreeSurface(bkg);
}

int main(int argc, char *argv[])
{

/* Initialize SDL's video system and check for errors. */
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("Unable to initialize SDL: %s\n", SDL_GetError());
return 1;
}
/* Make sure SDL_Quit gets called when the program exits! */
atexit(SDL_Quit);

screen = SDL_SetVideoMode(800,600,16,0);
if (screen == NULL) {
printf("Unable to set video mode: %s\n", SDL_GetError());
return 1;
}
screen = SDL_GetVideoSurface();

int quit;
quit = 0;
Uint8 *keystate;

while (quit == 0) {
	SDL_PumpEvents();
	keystate = SDL_GetKeyState(NULL);
	if (keystate[SDLK_q] || keystate[SDLK_ESCAPE]) quit = 1;

	startanim("000-sakura.bmp", 0, 4);
/* Ask SDL to update the entire screen. */
SDL_Flip(screen);
	
}

return 0;

}


[Edited by - Fujitaka on October 14, 2009 2:07:01 PM]

Share this post


Link to post
Share on other sites
Advertisement
Tips:
  • Use [code] ( lower-case "code") or maybe [source] tags

  • startanim creates and destroys a surface every frame. Why not keep a reference to it somewhere and load it just once?

  • I might be wrong, but I remember something about SDL_BlitSurface changing src or dest if any of them included an invalid area of the surface, but you could try to keep these outside the loop, since you load the same value into them every time:
    src.y = 0;
    src.w = 32;
    src.h = 48;
    dest.x = 0;
    dest.y = 0;
    dest.w = 32;
    dest.h = 48;
  • You call SDL_Flip a few times per frame, when you should try to do it just once per frame. Instead of updating the screen in startanim, ask it to draw only one frame, update the frame counter inside your main loop and SDL_Flip only in there
About the timing, I'd go with SDL_GetTicks(). It will return the number of miliseconds since the library initialization. With one call to it every frame, you can find the time passed between two frames, something like this:

Uint32 timeBefore = SDL_GetTicks();
Uint32 timeNow = timeBefore;
while (quit == 0)
{
timeNow = SDL_GetTicks();
Uint32 deltaTime = timeNow - timeBefore;
timeBefore = timeNow;
//deltaTime now contains the time between this and last frame in miliseconds
}

Share this post


Link to post
Share on other sites
Different computers will iterate through the same game loop at different speeds. This makes locking the animation updates to the frames per second of the game loop not ideal.
struct animation_frame
{
SDL_Surface *pSurface;
SDL_Rect src_rect;
size_t sequence;
Sint32 delay;
};

struct animation
{
std::vector<animation_frame> frames;
Uint8 current_frame;
Sint32 change_frame;
};
Say you have an animation that has 200ms between changing frames and our last iteration of the game loop took 12ms. We subtract 12 from the animation delay and see if we need to change the animation frame.

// delta is the time our last game loop iteration took to complete
my_animation.change_frame -= delta;


Now say we only had 9ms left on the change_frame before this iteration of the game loop - we would have -3ms for the change_frame variable. If the change_frame variable is less than or equal to 0 we change to the next frame (or if the last frame start over depending on your needs) and reset the change_frame counter to the delay for the next frame in the animation. Since we have an extra 3 ms we subtract this from the change_frame counter as well leaving 197ms. This gives us the continuity we are looking for.

// use while in case it was an exceptionally long frame
while ( my_animation.change_frame <= 0 )
{
// increment the frame but make sure we don't overstept our bounds
if (++my_animation.current_frame >= my_animation.frames.size() )
my_animation.current_frame=0;

// make sure we keep the time consistent
my_animation.change_frame += my_animation.frames[my_animation.current_frame].delay;
}

I have been using this method (although fleshed out a little) successfully for quite while. I hope you find it useful.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!