1

I'm trying to write a 2D game using python / pygame that blits several layers on top of one another every screen refresh. My basic setup is (from bottom to top):

  • Background: surface (non-transparent), scrolls at a different rate than rest
  • Midground: SRCALPHA transparent surface (static)
  • Player / Sprites / Enemies: sprite group
  • Forground: SRCALPHA transparent surface (static)

Right now, I'm blitting these four layers one on top of another every screen. The background scrolls at a different rate than the other three layers, which is why I have it separate from midground. As I have the game structured now, it runs on my fairly modest laptop at 60fps.

-BUT- I'm having trouble with the sprite group, which I'm blitting directly to the screen. Having to adjust the rect for every sprite according to my current viewport seems like an ugly way to program things, and I'd like a more elegant solution.

I'd love to blit the sprites to another transparent surface which I could manage, but therin lies my problem: I can't find a way of clearing a transparent layer that doesn't half my performance. Some of the setups I've tried:

  • I've tried filling the layer with a white surface with blend mode rgba_sub (surf.fill((255,255,255,255), area, BLEND_RGBA_SUB)) -- this is super, super slow
  • I've tried surface.copy() of a blank surface - this is faster, but still halves my fps
  • I've tried combining the sprites with the midground layer and using pygame.sprite.LayeredUpdates to update the sprites. This has no effect on performance, but does not work where the midground is transparent. I get trails of sprites over the background layer.

The best solution I've found so far is my current setup of drawing sprites directly to the screen. It looks great, runs fast, but is a pain to manage, as I have to make sure each sprites' rect is adjusted according to the viewport every frame. Its also making collision detection difficult.

Is there another quick way to clear a pygame transparent surface? Quick as in, can be done 60+ times a second? Alternately, is there a setup for my layers that would still accomplish the same effect?

drinkdecaf
  • 385
  • 2
  • 12

2 Answers2

2

I figured out a fast way of clearing a sprites only transparent layer by applying Peter's solution selectively to the layer:

for s in self.level.sprites:
  spritelayer.fill((0), s.rect)

This seems to be working fine (erasing everything each frame) and still runs at 60fps.

drinkdecaf
  • 385
  • 2
  • 12
1

The Surface.fill() will clear all R, G, B, and A values.

>>> img = pygame.image.load("hasalpha.png")
>>> print img.get_at((300, 300))
(238, 240, 239, 255)
>>> surface.fill(0)
>>> print img.get_at((300, 300))
(0, 0, 0, 0)

It sounds like this will do what you are describing. If you are trying to do something more specific with the alpha values the pygame.surfarray.pixel functions can give you directly editable values. That will be quick, but requires numpy as a dependency.

Peter Shinners
  • 3,686
  • 24
  • 24
  • This seems to run faster than surf.fill((255,255,255,255), area, BLEND_RGBA_SUB), but is still giving me halved performance when I run it on the whole layer. – drinkdecaf Sep 13 '11 at 00:51
  • Aha! But when I apply it only on the sprite rects, it runs FAST :D Thank you sir! – drinkdecaf Sep 13 '11 at 00:58