为什么Python上的这个小型(155行)Pacman游戏运行得如此之慢?

时间:2012-04-30 05:57:09

标签: python optimization pygame

我已经从主循环中删除了所有功能。我还优化了动态和静态对象的碰撞,大大减少了迭代次数。但是他的机器仍然很慢。我会发布整个文件以查找有人想要测试它的情况,但你可以跳转到主循环“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 ()

2 个答案:

答案 0 :(得分:2)

您正在重新绘制并在每个循环中屏幕整个屏幕。我没有测试你的程序,但是在我知道的pacman上,屏幕上只有5个移动的精灵,你应该尝试只对每一帧进行blit(当然,如果有其他变化,也是如此)。并且不要显示.flip(),只需更新您更改的屏幕区域(通常会加速很多)。

当然,你需要在每一帧都停止对屏幕进行消隐,并且会对更新内容进行大量管理。 pygame http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.DirtySprite中的脏精灵有一些额外的支持可以帮助你。或者你可以通过消隐它们在哪里的位置并将它们重新绘制到新位置来更新所有“活动”精灵(显然所有这些都在这两个区域中)。在列表中收集受影响的rects并将其传递给update_rects()而不是翻转屏幕。在每一帧中都不应该在pacman游戏中绘制墙壁......

答案 1 :(得分:0)

可能不是缓慢的重要来源,但是“while = = False:”需要比“不退出时”更多的字节码执行。