[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()