[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Optimising a tile map renderer



Hi,

I am trying to make a pygame version of SimCity using the open source
Micropolis engine.

The engine spits out a 2d array of tile indexes that form the world
map.

I am having problems getting it to run fast at decent resolutions...

Here is the code:
class Map:
   def __init__(self, engine):
       self.engine = engine

       tilesFileName = 'images/micropolisEngine/tiles.png'

       self.tileSize = micropolisengine.EDITOR_TILE_SIZE
       tileSize = self.tileSize
       self.tiles = pygame.image.load(tilesFileName).convert()
       self.tilesPerRow = self.tiles.get_width() / self.tileSize

       self.worldWidth = micropolisengine.WORLD_W
       self.worldHeight = micropolisengine.WORLD_H
       self.width = self.worldWidth * tileSize
       self.height = self.worldHeight * tileSize

   def draw(self, surface, view):
       engine = self.engine
       tileSize = self.tileSize

       for y in range(view.top / tileSize, view.bottom / tileSize +
1):
           for x in range(view.left / tileSize, view.right / tileSize
+ 1):
               tile = engine.getTile(x, y)

               if tile == micropolisengine.TILE_INVALID:
                   break

               # FIXME - why is blinking not working?
               if engine.blinkFlag and (tile &
micropolisengine.ZONEBIT) and not (tile & micropolisengine.PWRBIT):
                   index = micropolisengine.LIGHTNINGBOLT
               else:
                   index = tile &
micropolisengine.LOMASK

               # FIXME - why do we get these from the sim engine?
               if index > 960:
                   print "Tile (%d, %d) is out of bounds = %d" % (x,
y, tile)
                   break

               if index >= micropolisengine.TILE_COUNT:
                   break

               surface.blit(
                   self.tiles,
                   pygame.Rect(
                       x * tileSize - view.left,
                       y * tileSize - view.top,
                       tileSize,
                       tileSize),
                   pygame.Rect(
                       (index % self.tilesPerRow) * tileSize,
                       (index / self.tilesPerRow) * tileSize,
                       tileSize,
                       tileSize))

cProfile shows that the surface.blit and engine.getTiles calls are the
slow ones.

At this stage I can't do too much about getTiles, but I would like to
speed up the blitting.
Also I hope at one stage I can a list of 'dirty' tiles to reduce the
number of tiles to render, but that might take a while.

If it is not possible to do it fast with pygame are there any other
fast 2d python libraries?

I get about 37-40 FPS on my gaming rig at fullscreen 1280*1024:
Windows 7 64bit
ATI Radeon HD 5850
AMD Phenom II X4 @ 3.21GHz
4GB 1600 MHz DDR3