[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [pygame] Fast Scrolling

Damien Miller wrote:

> Can anyone point me to a good example of a fast scrolling background
> (full-screen or nearly full-screen)?

i wrote a pretty cool and fast scrolling tile engine for my 48 hour 
game. unfortunately i never got to creating an actual map to scroll 
around. here is a small cleaned up version of the scrolling code.
#!/usr/bin/env python
the Map class stores all the tiles in a big list. you can lookup
any tile by calling the "tile(x,y)" method. it does a little
voodoo to speed up the drawing loop. you call the draw() method
with a surface and "map x,y" position arguements. the x,y
coordinates are in actual pixels, and that will be the position
in the center of the screen. it allows for any size tiles and map.

i admit it's not written to be clear, as much turbo quick and
semi flexible. you can run it for a simple scrolling example
with the mouse. hopefully this is quick enough for you, i don't think it can
be much quicker with just python code. I've been thinking about
a C function in pygame to blit a "row" of images. But I'm not
certain that would make a noticeable difference?

Pete Shinners, November 21, 2002
import pygame, random
from pygame import *

TILESIZE = 64, 64
MAPSIZE = 30, 30

class Tile:
    blocked = 0
    def __init__(self):
        #make a random colored block
        color = map(random.randint, [0]*3, [255]*3)
        self.image = pygame.Surface(TILESIZE).convert()

class Map:
    def __init__(self):
        #initialize variables
        tilew, tileh = TILESIZE
        self.drawloop = [((x+1), (y+1), (x-1)*tilew, (y-1)*tileh+2)
                for y in range(480/tileh+2) for x in range(640/tilew+2)]
        self.tilesx, self.tilesy = MAPSIZE
        self.tilew = tilew
        self.tileh = tileh

        #fill the map with tiles
        self.tiles = [Tile() for x in range(self.tilesx*self.tilesy)]
        self.outofbounds= self.tiles[0]

    def tile(self, x, y): 
        if x<0 or y<0 or x>=self.tilesx or y>=self.tilesy:
            return self.outofbounds
        return self.tiles[y*self.tilesx+x]

    def draw(self, screen, px, py):
        px -= screen.get_rect().centerx
        py -= screen.get_rect().centery
        xoffs = self.tilew - (px % self.tilew)
        yoffs = self.tileh - (py % self.tileh)
        xtile = px / self.tilew
        ytile = py / self.tileh	

        blit = screen.blit
        for x,y,xpos,ypos in self.drawloop:
            tile = self.tile(x+xtile, y+ytile)
            pos = xpos+xoffs, ypos+yoffs
            blit(tile.image, pos)

if __name__ == '__main__': #test it out
    import pygame
    screen = pygame.display.set_mode((640, 480), flags)
    posx, posy = 800, 800
    map = Map()

    timer = pygame.time.Clock()
    pygame.time.set_timer(USEREVENT, 1000)
    font = pygame.font.Font(None, 40)
    message = None

    while 1:
        for e in pygame.event.get():
            if e.type == QUIT: raise SystemExit, "QUIT"
            if e.type == KEYDOWN and e.key == K_ESCAPE: raise SystemExit, "ESCAPE"
            if e.type == MOUSEMOTION:
                posx -= e.rel[0]
                posy -= e.rel[1]
            elif e.type == USEREVENT:
                s = "Frames Per Second: %.2f" % timer.get_fps()
                message = font.render(s, 0, (255,255,255)).convert()
        map.draw(screen, posx, posy)
        if message: screen.blit(message, (0,0))