如果在非常相似的障碍物中通过pygame碰撞检查碰撞,我怎样才能提高性能?

时间:2015-02-03 16:22:20

标签: python pygame

编辑:QuadTrees(http://www.pygame.org/wiki/QuadTree?parent=CookBook)可能是我的答案,试试这个并报告回来。不管怎样,请不要犹豫,给我一些建议!

我在pygame中有一系列障碍,我正在转换为Rect对象,在帧的每个刻度之前循环遍历列表,以查看我的Hero Rect对象是否已经碰撞。

我认为这会导致我出现性能问题。我也知道我可以尝试切换到" Dirty rect animation"而不是每次打勾都更新整个屏幕,但在我走这条路之前,我想知道我是否能更有效地做到这一点。

有问题的特定代码发生在最底层附近(如果是pillars.checkCollision(hero.rect):),但我提供了上下文的所有内容:

import sys
import pygame
from pygame.locals import *
import pyganim
from decimal import *
import math

## start pymgame
pygame.init()

## window and lines
windowWidth = 387
windowHeight = 340
lineThickness = 3
animationSpeed = .15

## fps and speed
increaseSpeed = 1
fps = 60
fpsClock = pygame.time.Clock()

## window
##windowSurface = pygame.display.set_mode((windowWidth, windowHeight), pygame.FULLSCREEN)
windowSurface = pygame.display.set_mode((windowWidth, windowHeight))

class Pillars():
    def __init__(self):
        self.image = pyganim.PygAnimation([("grave.png", animationSpeed)])
        self.xSize = self.image.getMaxSize()[0]
        self.ySize = self.image.getMaxSize()[1]
        self.numberOfColumns = int(math.ceil(Decimal((windowWidth - (self.xSize * 4))) / Decimal((self.xSize * 3))))
        self.numberOfRows = int(math.ceil(Decimal((windowHeight - (self.ySize * 4))) / Decimal((self.ySize * 3))))
        self.rects = []
        self.image.play()

    def draw(self):
        xPos = (self.xSize * 2)
        yPos = (self.ySize * 2)
        columnCounter = 1
        for num in range(0, (self.numberOfColumns * self.numberOfRows)):
            self.rects.append(Rect(xPos, yPos, self.xSize, self.ySize))
            self.image.blit(windowSurface, (xPos, yPos))
            xPos += (self.xSize * 3)
            if columnCounter >= self.numberOfColumns:
                columnCounter = 0
                xPos = (self.xSize * 2)
                yPos += (self.ySize * 3)
            columnCounter += 1

    def checkCollision(self, Rect):
        for pillarRect in self.rects:
            if pillarRect.colliderect(hero.rect):
                return True



class Hero():
    def __init__(self):
        self.standingLeft = pyganim.PygAnimation([("left_standing_link.png", animationSpeed)])
        self.standingRight = pyganim.PygAnimation([("right_standing_link.png", animationSpeed)])
        self.standingUp = pyganim.PygAnimation([("up_standing_link.png", animationSpeed)])
        self.standingDown = pyganim.PygAnimation([("down_standing_link.png", animationSpeed)])
        self.walkingUp = pyganim.PygAnimation([("up_standing_link.png", animationSpeed), ("up_walking_link.png", animationSpeed)])
        self.walkingDown = pyganim.PygAnimation([("down_standing_link.png", animationSpeed), ("down_walking_link.png", animationSpeed)])
        self.walkingLeft = pyganim.PygAnimation([("left_standing_link.png", animationSpeed), ("left_walking_link.png", animationSpeed)])
        self.walkingRight = pyganim.PygAnimation([("right_standing_link.png", animationSpeed), ("right_walking_link.png", animationSpeed)])
        self.walkingRight.play()
        self.walkingLeft.play()
        self.standingLeft.play()
        self.standingRight.play()
        self.standingUp.play()
        self.standingDown.play()
        self.walkingUp.play()
        self.walkingDown.play()
        self.x = 100
        self.y = 100
        self.dirX = 0 ## -1 = left 1 = right
        self.dirY = 0 ## -1 = up 1 = down
        self.orientation = 0 ## 0 = right, 1 = down, 2 = left, 3 = up
        self.rect = None

    def move(self, animationObj):
        self.animationObject = animationObj
        animationObj.x = self.x + (self.dirX * increaseSpeed)
        animationObj.y = self.y + (self.dirY * increaseSpeed)
        self.x = animationObj.x
        self.y = animationObj.y
        if self.dirX == 1:
            self.orientation = 0
        elif self.dirX == -1:
            self.orientation = 2
        elif self.dirY == -1:
            self.orientation = 3
        elif self.dirY == 1:
            self.orientation = 1
        tempRect = animationObj.getRect()
        self.rect = Rect(animationObj.x, animationObj.y, tempRect[2], tempRect[3])

    def draw(self, animationObj):
        if self.y > (windowHeight - (lineThickness * 5.5)):
            self.y = windowHeight - (lineThickness * 5.5)
        elif self.y < lineThickness:
            self.y = lineThickness
        elif self.x > (windowWidth - (lineThickness * 6)):
            self.x = windowWidth - (lineThickness * 6)
        elif self.x < lineThickness:
            self.x = lineThickness        
        animationObj.blit(windowSurface, (self.x, self.y))    

    def moveAndDrawWalkingRight(self):

        self.dirX = 1
        self.dirY = 0
        self.move(self.walkingRight)
        self.draw(self.walkingRight)

    def moveAndDrawWalkingLeft(self):

        self.dirX = -1
        self.dirY = 0
        self.move(self.walkingLeft)
        self.draw(self.walkingLeft)

    def moveAndDrawWalkingUp(self):

        self.dirX = 0
        self.dirY = -1
        self.move(self.walkingUp)
        self.draw(self.walkingUp)

    def moveAndDrawWalkingDown(self):

        self.dirX = 0
        self.dirY = 1
        self.move(self.walkingDown)
        self.draw(self.walkingDown) 

    def drawStanding(self):
        if self.orientation == 0:
            self.dirX = 0
            self.dirY = 0
            self.move(self.standingRight)
            self.draw(self.standingRight)
        elif self.orientation == 2:
            self.dirX = 0
            self.dirY = 0
            self.move(self.standingLeft)
            self.draw(self.standingLeft)
        elif self.orientation == 1:
            self.dirX = 0
            self.dirY = 0
            self.move(self.standingDown)
            self.draw(self.standingDown)
        elif self.orientation == 3:
            self.dirX = 0
            self.dirY = 0
            self.move(self.standingUp)
            self.draw(self.standingUp)  

def drawArena():
    windowSurface.fill((0,0,0))

hero = Hero()
pillars = Pillars()

while True: # main loop

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
##            if event.key == K_RIGHT:
##                hero.moveAndDrawWalkingRight()
##            elif event.key == K_LEFT:
##                hero.moveAndDrawWalkingLeft()
##            elif event.key == K_UP:
##                hero.moveAndDrawWalkingUp()
##            elif event.key == K_DOWN:
##                hero.moveAndDrawWalkingDown()
##        else:
##            hero.drawStanding()

    drawArena()
    pillars.draw()

    priorHeroX = hero.x
    priorHeroY = hero.y

    keys = pygame.key.get_pressed()  #checking pressed keys

    if keys[pygame.K_RIGHT]:
        hero.moveAndDrawWalkingRight()
    elif keys[pygame.K_LEFT]:
        hero.moveAndDrawWalkingLeft()
    elif keys[pygame.K_UP]:
        hero.moveAndDrawWalkingUp()
    elif keys[pygame.K_DOWN]:
        hero.moveAndDrawWalkingDown()
    else:
        hero.drawStanding()

    if pillars.checkCollision(hero.rect):
        hero.x = priorHeroX
        hero.y = priorHeroY

    pygame.display.update()
    fpsClock.tick(fps)

1 个答案:

答案 0 :(得分:1)

不是使用Rect检查每个.colliderect(..),而是可以像.collidelist(..)一样使用 .. # in class Pillars .. def checkCollision(self): # `Rect` was in there as an argument; I'm not sure what it did...? if hero.rect.collidelist(self.rects) != -1: # collidelist returns a list index if it collides, or -1 if it does not. return True

def checkCollision(self):
    return False if hero.rect.collidelist(self.rects) == -1 else True
    # Be aware that this returns False instead of nothing if there is no collision.

......甚至只是......

Rect

我不确定Pygame是否有比你的循环更有效的迭代器,但可能呢?如果不出意外,它会为您节省几行代码。如果您需要知道具体与hero def getColliding(self): # this returns something slightly different... idx = hero.rect.collidelist(self.rects) return None if idx == -1 else self.rects[idx] 发生冲突,请考虑以下事项:

Rect

如果有hero对象发送回None对象,或者如果有多个就发送回列表中的第一个这样的Rect,或者{{1}}如果没有碰撞完全没有。