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

Re: [pygame] Fast Scrolling



Rene Dudfield wrote:
> I rewrote the draw function to cache some data, and
> then make one call to blit:
> 
> map(screen.blit,
> self.cached_tiles[(px,py)],self.cached_tiles2[(px,py)]
> )
> 
> This speeds it up on my box to about 55 fps from 47
> fps.  When moved though the frame rate drops a bit
> more than it normally does(not by much more).
> 
> Of course if the mouse position is moved lots, heaps
> of memory can be used in the cache.  Then if it swaps
> the frame rate will drop lots!

nifty idea. i've changed it to toggle between two overlapping caches.
this means the memory will never get out of control, but likely be
the exact same speed.

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()
        self.image.fill(color)

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]

	self.maincache = {}
	self.backcache = {}
	self.cachemax, self.cachestart = 200, 70

    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):
	#print "top", (px, py)

	screendraw = self.maincache.get((px, py)) #None if not found
	if screendraw:
	    map(screen.blit, *screendraw)
	else:
	    px_new = px - screen.get_rect().centerx
	    py_new = py - screen.get_rect().centery
	    xoffs = self.tilew - (px_new % self.tilew)
	    yoffs = self.tileh - (py_new % self.tileh)
	    xtile = px_new / self.tilew
	    ytile = py_new / self.tileh

	    blit = screen.blit

            im_pos = []
            im_pos_append = im_pos.append
            im_pos2 = []
            im_pos2_append = im_pos2.append

            self_tile = self.tile

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

	    if len(self.maincache) > self.cachemax:
		self.maincache, self.backcache = self.backcache, {}
	    elif len(self.maincache) > self.cachestart:
		self.backcache[ (px, py) ] = im_pos, im_pos2
            self.maincache[ (px,py) ] = im_pos, im_pos2

	    print len(self.maincache), len(self.backcache)




def main():
    import pygame
    pygame.init()
    flags = 0 #FULLSCREEN|DOUBLEBUF
    screen = pygame.display.set_mode((640, 480), flags)
    print screen
    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:
        timer.tick()
        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))
	pygame.display.flip()




if(__name__ == "__main__"):
    import sys
    if len(sys.argv) != 1:
        if sys.argv[1] == "profile":
            #import profile
            #profile.run('main()', '/tmp/prof')

            import hotshot
            prof = hotshot.Profile('/tmp/prof')
            prof.run('main()')

    else:

        main()