Cleaning up old sprites in PyGame?


RndmNumGenerator

Still Fresh
Joined
Sep 2, 2011
Messages
4
I'd decided to pick up Python over the summer so I could begin working on app development for android phones. After getting the basics down, my first project was making a simple adventure roguelike game using the Pygame library, but I'm having problems with the pygame graphics I can't work out.


Basing my game off of tutorials and example code, I've got everything working so far except rendering the sprites(or sprite, more accurately. At this point I only have the player in the game). I can render him to the screen just fine, but the problem is when I move him - he gets rendered at his new location, but doesn't stop being rendered where he was previously. So when he moves, he leaves a trail of himself behind.


I think I could just re-render the entire background to cover the old sprites up, but that seems horribly inefficient. Is there a way to just re-render the parts that need it? Or just clean up old instances of the sprite? Before Python I was using ActionScript, where all you needed to do was move the sprite's x and y position and Flash would do all the rest... I guess Python needs something more.


I would appreciate any help you could give.

Untitled.jpg
 
Hi 4 ;) , welcome to the boards.


I don't have too much experience using Pygame, but I know python. Reading through the Pygame documention reveals the display.update method



Code:
game.display.update:

update portions of the screen for software displays


pygame.display.update(rectangle=None): return None

pygame.display.update(rectangle_list): return None

It seems to accept an optional rectangle or rectangle list such that it only redraws the dirty rectangles. I'm assuming these need to be pygame.Rect objects.
 
That's just for updating the screen, not actually changing the rendering position of objects. However, that did give me an idea for how to run it; before changing the player's position, I can re-render the single tile of the map he was standing on, update that tile then change the player's position and update his new tile. Works great. So thanks for the idea!
 
^ That will work only so long as your player moves in whole tile increments, which might be the case here but you will probably need to find another way if you move onto more advanced projects.
 
^ And that would be (for example) pre-rendering the unchanging bits of the background to a buffer and copying rects from that buffer to the screen buffer when erasing sprites. If your sprites intersect, do a quick rect-collision test to see whether you need to repaint some of the other sprites too.
 
Last edited by a moderator:
^ I'm not sure what you mean by pre-rendering the unchanging bits to a buffer... Could you elaborate? It is true that my solution only works for tiles, so while I can use it now it won't work in a non-tile based game.
 
Create a game area sized back buffer, render the unchanging parts of the scene there once, and use this buffer to erase stuff from the display buffer. This way you only need to draw the static stuff once. Though it's actually best used when the scene is not huge and has little parallaxing and stuff. In your case (judging by the picture you provided) you'd draw the tiles to a buffer, then copy from that buffer when erasing the sprites. It's a trick that works sometimes, and doesn't apply to nearly every situation, but seemed approprieate for this occasion.
 
Indeed. Just create an image with exactly one copy of all your tiles in it in a grid. That way you can construct the background image for your dungeons by copying the correct tiles and you add support for custom tilesets for free. Whenever you need to erase an image you look up the proper tile underneath and copy it over.
 
You may find this interesting:


http://www.pygame.or...ewbieguide.html


Short but interesting reading!


Extract:

  1. Blit a piece of the background over the sprite's current location, erasing it.
  2. Append the sprite's current location rectangle to a list called dirty_rects.
  3. Move the sprite.
  4. Draw the sprite at it's new location.
  5. Append the sprite's new location to my dirty_rects list.
  6. Call display.update(dirty_rects)



:D


For my many many unfinished games and game engines, I used a list to record "dirty rects" from bottom to top layer. The display.update PyGame method handles the merging of rects to avoid multiple renderings, so don't bother trying to optimize this list.
 
Last edited by a moderator:
That's just for updating the screen, not actually changing the rendering position of objects. However, that did give me an idea for how to run it; before changing the player's position, I can re-render the single tile of the map he was standing on, update that tile then change the player's position and update his new tile. Works great. So thanks for the idea!

He's right, you know. The only things he's missing are the pygame.sprite.Group.clear method, which draws the background only where the screen was drawn to last, and the pygame.sprite.RenderUpdates.draw method, which draws the sprites and returns a list of rects for you to pass to pygame.display.update. Here's an example of a redraw that occurs every frame from one of my games, where self.all is a pygame.sprite.RenderUpdates object, self.window is a surface returned by pygame.display.set_mode(), and self.background is the background surface:



Code:
self.all.clear(self.window, self.background)

self.all.update()

dirty = self.all.draw(self.window)

pygame.display.update(dirty)


As a side note, don't worry too much about efficiency until it's actually a problem. What's most important is that your game runs smoothly at full speed (or at 60 FPS, if you're using delta timing) on the weakest machine you expect it to run on, and if it does that, there's no need to attempt complicated solutions to making your game run even faster.
 
Last edited by a moderator:
Back
Top