Animating a Sprite in SDL
Ok I read the tutorial on it cone3d.gamedev.net. So do the sprites I want to animate have to be a animated gif or can it be a series of bitmaps?
A series of bitmaps is how I would do it. Its much easier then extracing the gif data.
Quote:Original post by DevLiquidKnight
A series of bitmaps is how I would do it. Its much easier then extracing the gif data.
In addition, not just a series of seperate files, but rather a BMP sheet of the sprites could be an effecient way to do it as well. With SDL, it's really easy to use sprite sheets too.
To elaborate a bit on the previous post, for a sprite sheet all you need to do to animate it is, instead of resetting the sprite variable or iterating through an array, just make a class or structure so that telling it to switch to a different frame results in the image's src_rect being moved to the appropriate section of the image.
Ummmm. The only example of actual code I have on hand is in O'Caml. I would translate it to C, but knowing me I'd mess something up and only confuse you more. But here goes...
So to actually use this we'd do something like
Then image.bmp is just a single bitmap that has all the different animation frames you want for whatever particular effect.
Hope that helps. I apologize for the obscure code, but I can't stand C++.
class sprite =object (self) val img = loadBMP "image.bmp" val imgw = (* whatever the total image width is *) val imgh = (* whatever the total image height is *) val mutable numframes = (* However many frames you have *) val mutable currentframe = 0 (* This is the SDL_rect that tells us where on img we want to blit from We're going to "scroll" this back and forth along the image's X axis to change frames in the animation *) val frame = {r_x = 0; r_y = 0; r_w = 0; r_h = 0} (* This is the SDL_rect that tells us where on whatever surface we want to blit to *) val dest = {r_x = 0; r_y = 0; r_w = 0; r_h = 0} (* We initialize the rects with the correct width and height... we're only going to be moving the frame along the X axis, since it's simpler *) initializer frame.r_w <- imgw / numframes; frame.r_h <- imgh; dest.r_w <- frame.r_w; dest.r_h <- imgh; (* Methods to get current animation index and to move the frame to a new animation *) method getCurrentFrame = currentframe method setFrame n = currentframe <- n mod numframes; frame.r_x <- currentframe * frame.r_w method nextFrame = currentframe <- (currentframe + 1) mod numframes; self#setFrame currentframe method prevFrame = currentframe <- abs ((currentframe - 1) mod numframes); self#setFrame currentframe (* Sets the destination rect to wherever we want *) method moveTo x y = dest.r_x <- x; dest.r_y <- y (* This actually blits our image to the given surface *) method blit dst = (* We make sure the destination coordinates are actually inside the surface *) let dstw, dsth, _ = (surface_dims dst) in if dest.r_x > dstw || dest.r_y > dsth then () else blit_surface ~src: img ~src_rect: frame ~dst: dst ~dst_rect: dest ();end;;
So to actually use this we'd do something like
(* Set up video mode, yadda yadda *)Sdl.init [`EVERYTHING];let oursprite = new sprite inlet screen = Sdlvideo.set_video_mode ~w: 640 ~h: 480 ~bpp: 16 [] inoursprite#moveto 100 100;while true do oursprite#nextFrame; oursprite#blit screen; flip screen;done;Sdl.quit ();
Then image.bmp is just a single bitmap that has all the different animation frames you want for whatever particular effect.
Hope that helps. I apologize for the obscure code, but I can't stand C++.
If you take a look at the SDL_BlitSurface function, you notice a couple things:
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
See the srcrect parameter? You can use this to denote where on the surface you are going to be blitting from. If you make a new rectangle object and set it to the individual tile on the surface, you can effectively make it blit only one segment of the sprite tile sheet. I'll let you figure out your own implementation of it as that's the only way you'll truly learn [smile].
Awhile ago I wrote a c++ class for dealing with SDL_Surface. You can take a look at it here. It comes with a example app showing a basic way to do some animation with a sprite sheet.
It only has a Makefile, so if you're not using some form of unix you'll probably need to create your own project in whatever dev environment you're using.
I'm also planning on cleaning it up at some point in the future - the graphics could definately use some work, but feel free to learn from it or use it.
It only has a Makefile, so if you're not using some form of unix you'll probably need to create your own project in whatever dev environment you're using.
I'm also planning on cleaning it up at some point in the future - the graphics could definately use some work, but feel free to learn from it or use it.
@WillF
I tried to compile your code but when it exucutes it just flashes the window and closes itself
@Rob I tried what you said and got it to blit each frame if I changed the CURRENT_FRAME value manually before I compile but when I try to advance the frame in my while loop it does nothing. I'm going to post my code to see if you can see what's wrong.
[Edited by - rpgman15 on July 20, 2005 5:17:22 PM]
I tried to compile your code but when it exucutes it just flashes the window and closes itself
@Rob I tried what you said and got it to blit each frame if I changed the CURRENT_FRAME value manually before I compile but when I try to advance the frame in my while loop it does nothing. I'm going to post my code to see if you can see what's wrong.
#include stdio.h;#include stdlib.h;#include SDL/SDL.h;SDL_Surface *back;SDL_Surface *screen; #define NUM_FRAMES 10int CURRENT_FRAME = 0;int xpos2 = 27 * CURRENT_FRAME;int ypos2 = 3;int xpos = 300;int ypos = 400;int InitImages(){ back = SDL_LoadBMP("Gfx/A_WALK_D.bmp"); return 0;}void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2){ SDL_Rect dest; dest.x = x; dest.y = y; SDL_Rect dest2; dest2.x = x2; dest2.y = y2; dest2.w = w; dest2.h = h; SDL_BlitSurface(back, &dest2, screen, &dest);}void DrawSprite(){ DrawIMG(back, xpos, ypos,27,46,xpos2,ypos2); }void AdvanceFrame(){ CURRENT_FRAME plusplus; if(CURRENT_FRAME > 10) { CURRENT_FRAME = 0;}} void DrawScene(){ DrawSprite(); AdvanceFrame();}int main(int argc, char *argv[]){ Uint8* keys; InitImages(); if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ) { printf("Unable to init SDL: %s\n", SDL_GetError()); exit(1); } atexit(SDL_Quit); SDL_WM_SetCaption("DarkSword","darksword"); screen=SDL_SetVideoMode(800,600,32,SDL_HWSURFACE|SDL_DOUBLEBUF); if ( screen == NULL ) { printf("Unable to set 800x600 video: %s\n", SDL_GetError()); exit(1); } DrawScene(); int done=0; SDL_Event event; while(done == 0) while ( SDL_PollEvent(&event) ) { if ( event.type == SDL_QUIT ) { done = 1; } if ( event.type == SDL_KEYDOWN ) { if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; } } DrawScene(); } return 0;}
[Edited by - rpgman15 on July 20, 2005 5:17:22 PM]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement