Why is this small (155 lines-long) Pacman game on Python running so slow?

匿名 (未验证) 提交于 2019-12-03 01:38:01

问题:

I have already cut everything I could from the main loop. I also optimized collisions for dynamic and static objects, reducing considerably the number of iterations. But it is still slow on his machine. I'll post the entire file for the case someone wants to test it, but you can just jump to the main loop at "while Exit==false:".

import pygame from pyeuclid import Vector2 from math import sin,cos,pi from random import random  class Thing:     def __init__(self,pos):         self.pos = pos         things.append(self)     def update(self): pass     def draw(self,img): pass     def collide(self,who): pass  class DynamicThing(Thing):     def __init__(self,pos):         Thing.__init__(self,pos)         self.vel = Vector2(0,0)         self.lastPos = pos         self.col = (255,255,0)         self.r = 12         dynamic_things.append(self)     def update(self):         self.lastPos = self.pos         self.pos = self.pos + self.vel     def draw(self,img):         pygame.draw.circle(img, (0,0,0), [int(n) for n in self.pos], self.r, self.r)         pygame.draw.circle(img, self.col, [int(n) for n in self.pos], self.r-2, self.r-2)     def collide(self,obj):         Thing.collide(self,obj)         if isinstance(obj,Wall):              self.pos = self.lastPos  class Wall(Thing):     def draw(self,img):         x,y = self.pos.x, self.pos.y         pygame.draw.rect(img, (90,90,200), (x-16,y-16,32,32), 0)  class Pacman(DynamicThing):     def __init__(self):         DynamicThing.__init__(self,Vector2(32*9+16,32*12+16))         self.col = (255,255,0)     def update(self):         DynamicThing.update(self)         if (keyPressed[pygame.K_LEFT]): self.vel.x = -1         if (keyPressed[pygame.K_RIGHT]): self.vel.x = 1         if (keyPressed[pygame.K_DOWN]): self.vel.y = 1         if (keyPressed[pygame.K_UP]): self.vel.y = -1         if (self.vel.x==-1 and not keyPressed[pygame.K_LEFT]): self.vel.x = 0         if (self.vel.x==1 and not keyPressed[pygame.K_RIGHT]): self.vel.x = 0         if (self.vel.y==1 and not keyPressed[pygame.K_DOWN]): self.vel.y = 0         if (self.vel.y==-1 and not keyPressed[pygame.K_UP]): self.vel.y = 0     def collide(self,obj):         DynamicThing.collide(self,obj)         if isinstance(obj,Ghost):             self.pos = Vector2(32*9+16,32*12+16)  class Ghost(DynamicThing):     def __init__(self):         DynamicThing.__init__(self,Vector2(32*9+16,32*10+16))         self.col = (int(random()*255),int(random()*255),int(random()*255))         self.vel = Vector2(0,-2)     def update(self):         DynamicThing.update(self)         if random()<0.01:             self.vel = [Vector2(2,0),Vector2(-2,0),Vector2(0,2),Vector2(0,-2)][int(random()*4)]     def collide(self,obj):         DynamicThing.collide(self,obj)         if isinstance(obj,Wall):             self.vel = [Vector2(2,0),Vector2(-2,0),Vector2(0,2),Vector2(0,-2)][int(random()*4)]  def thingAtPos(pos):     tile_pos = Vector2(int(pos.x/32),int(pos.y/32))     return map[tile_pos.y][tile_pos.x]  # initializate stuff pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode([32*19,32*22]) points_in_unit_circle_border = [Vector2(cos(float(a)/8*2*pi),sin(float(a)/8*2*pi)) for a in xrange(8)] things = [] dynamic_things = [] exit = False  map =  [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],         [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1],         [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1],         [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1],         [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],         [1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1],         [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1],         [1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1],         [1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1],         [1,1,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1],         [1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1],         [1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1],         [1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1],         [1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1],         [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1],         [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1],         [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],         [1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1],         [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1],         [1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1],         [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],         [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]   #create pacman, walls, ghosts pacman = Pacman() for y in xrange(len(map)):     for x in xrange(len(map[y])):         if (map[y][x]==1):             map[y][x] = Wall(Vector2(x*32+16,y*32+16)) for i in xrange(4):     Ghost()  while exit==False:     clock.tick(45)      screen.fill([255,255,255])     keyPressed = pygame.key.get_pressed()      # events     for event in pygame.event.get():         if event.type == pygame.QUIT:             exit = True         if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:             exit = True      # more ghosts     if random()<0.001: Ghost()      # updates e draws     for thing in things:         thing.update()         thing.draw(screen)      # collisions     for A in dynamic_things:         #dynamic vs dynamic         for B in dynamic_things:             if A!=B and abs(A.pos-B.pos)<(A.r+B.r):                 A.collide(B)                 B.collide(A)         #dynamic vs walls         for circle_point in points_in_unit_circle_border:             thing_in_a_border = thingAtPos(A.pos+circle_point*12)             if isinstance(thing_in_a_border,Wall):                 A.collide(thing_in_a_border)      pygame.display.flip()  pygame.quit () 

回答1:

You are redrawing and fliping the whole screen in every loop. I didn't test your program, but on the pacman I know, there are only 5 moving sprites on the screen, you should try to only blit those every frame (and of course if something else changes, that too). And don't display.flip(), just update the areas of the screen that you changed (that normally speeds up a lot).

Of course you need to stop blanking the screen every frame for that, and there will be much management of what to update. There is some extra support for dirty sprites in pygame http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.DirtySprite that help you with that. Or you could maybe just update all 'active' sprites by blanking the position they where and redrawing them in the new position (and obviously everything that also is in those two areas). Collect the effected rects in a list and pass that to update_rects() instead of flipping the screen. There should be no need in drawing the walls in a pacman game in every frame...



回答2:

Probably not a big source of slowness, but "while exit==False:" requires a little more bytecode to execute than "while not exit:".



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!