SDL lag when blitting
I'm pretty new to programming and I have spent some time learning to use SDL in order to make a simple 2d game.
When I update the screen I blit the map/background and then I blit the moving things (player controlled character, etc) on top of it. I do this with a frame rate of 40 fps.
The problem is that this seems to cause lag. I think it would make sense to remove the blitting of the map (since the map doesn't change in every frame) and just blit the map ones at the start of the game. However, this will make the character leave a trail of blitted images behind (since they are left on top of the map).
My question is: is there a way to update the screen in a more efficent way, so the lag is reduced, without leaving the old images?
Each time you place a character on screen, you do
- save the bitmap of where the character is going to be placed.
- draw the character.
Each time you erase a character (in preparation to draw it somewhere else), you do
- copy the save bitmap back to the screen bitmap.
Ideally, you to all of this on an off-screen buffer. When you're done updating the off-screen buffer, you can either
- copy the whole off-screen to on-screen
- just copy the modified rectangle(s)
I think I understand what you mean, but I'm not sure how to actually implement it into the program. The erase part is what I have trouble with. How do I copy the bitmap back to the screen bitmap when it's already blitted and flipped?
I would redraw the entire screen (via double buffering) and use layering or draw order to achieve what you want.
You could try speeding up the rendering a little bit; perhaps the lag won't matter so much if you have a faster frame rate. In terms of the SDL, if you create your video surface with the SDL_HWSURFACE video flag (to try to put the surface in hardware memory), you may get better performance. Double-buffering is quite simple, I believe you just have to initialize it and call SDL_Flip() when you want to swap the double buffers. Also make sure your bitmaps are the right format (using SDL_DisplayFormat or SDL_DisplayFormatAlpha) to match the screen; otherwise the SDL will be converting surfaces on the fly to the right depth-per-pixel, which is very slow!
You can play around with updating only those rects that have changed; I tried this in one project (atlantis, see signature), and it really was more trouble than it's worth in my opinion. If you use double-buffering and a couple of coarse checks so that you don't do silly things like painting six maps on top of each other or painting all one-hundred offscreen sprites simultaneously, computers are fast enough these days that you can redraw the entire screen. As VirtualAce (whom I still think of as Bubba . . .) says, you can create some layers to render say the map to a surface and then blit that surface all at once whenever you need to redraw the screen. Give it a shot, see what happens.
Thanks for the advice!
Originally Posted by dwks
I tried to increase the desired frame rate in the code, but what happens is that the frame rate seems to drop to around 10-20 FPS no matter how high I set it.
I've tried both SDL_HWSURFACE and SDL_SWSURFACE in the SDL_SetVideoMode, but it makes no visible difference when it comes to performance and frame rate.
I tried using SDL_DisplayFormat, but it made all the transparent parts in my png sprites white, so I removed it. I know that you can create transparency in the code by making a specific color transparent, but I haven't done that. Is it worth doing, or is there another way?
I'm not entirely sure about all the programming terms, but I think that I am double-buffering. I'll post some of the code if you want to look at it yourself. Starting with the loop for the game itself (it's not really finished yet as you can see)
SDL_Flip( screen );
if(SDL_PollEvent( &event ))
if(event.type == SDL_QUIT)
for( int a = 0; a < (SCREEN_HEIGHT/16); a++)
for( int b = 0; b < (SCREEN_WIDTH/16); b++)
offset.x = (b)*16;
offset.y = (a)*16;
SDL_BlitSurface( tiles, &clip[ map[a][b] ], screen, &offset );
if( charDirection == 1 ) charPosition.y -= speed;
else if( charDirection == 0 ) charPosition.y += speed;
else if( charDirection == 3 ) charPosition.x -= speed;
else if( charDirection == 2 ) charPosition.x += speed;
if( collision( charPosition.x, charPosition.y ) )
if( charDirection == 1 ) charPosition.y += speed;
else if( charDirection == 0 ) charPosition.y -= speed;
else if( charDirection == 3 ) charPosition.x += speed;
else if( charDirection == 2 ) charPosition.x -= speed;
keystate = SDL_GetKeyState(NULL);
if( keystate[SDLK_w] || keystate[SDLK_UP] ) charDirection = 1;
else if( keystate[SDLK_s] || keystate[SDLK_DOWN] ) charDirection = 0;
else if( keystate[SDLK_a] || keystate[SDLK_LEFT] ) charDirection = 3;
else if( keystate[SDLK_d] || keystate[SDLK_RIGHT] ) charDirection = 2;
bool collision(int x, int y)
int xTile = x/16;
int yTile = y/16;
int xTileEnd = ( x+16 )/16;
int yTileEnd = ( y+16 )/16;
if( walkable[yTile][xTile] == false ) return true;
else if( walkable[yTile][xTileEnd] == false ) return true;
else if( walkable[yTileEnd][xTile] == false ) return true;
else if( walkable[yTileEnd][xTileEnd] == false ) return true;
else return false;
SDL_BlitSurface( character, &clipChar[(charDirection*3)+status], screen, &charPosition );
if( timer == ANIMATION_DELAY )
timer = 0;
if(status < 2) status = 2;
else if(status == 2) status = 1;
Thanks for the help everyone! Using SDL_DisplayFormatAlpha( loadedImage ) when I load the images solved the problem.