PyGame中的Sprite碰撞测试(尝试过:rect和group)

时间:2017-05-19 00:55:37

标签: python pygame collision

我知道有近5或6个类似于我正在制作的问题,但没有一个答案对我有帮助(如果我不是一个完整的菜鸟,他们可能就会这样),所以我会尝试展示我的具体案例。

我正在尝试在PyGame(Python lib)中进行sprite碰撞测试,但是我无法让它工作,碰到时我得到的都是“False”,它根本不起作用我不能找出原因,一直在寻找2天。

在我的游戏中,我有对象Player(我称之为“dude”)和对象Enemy(我称之为“敌人”)。两者上的__init__非常相似,都生成了rects。

这是玩家的__init__

class dude(pygame.sprite.Sprite):
def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = self.load_image(SPRITE_PLAYER)
    self.X = randint(34,ALTURA-10)
    self.Y = randint(34,LARGURA-10)
    self.rect = pygame.Rect(self.X,self.Y,25,25) #currently testing this
    #self.rect = self.image.get_rect()           already tried this
    self.speed = SPEED_PLAYER
    self.clock = pygame.time.Clock()

对于敌人,我有这个:

class enemy(pygame.sprite.Sprite):
def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = self.load_image(SPRITE_ENEMY)
    self.X = randint(34,ALTURA-10)
    self.Y = randint(34,LARGURA-10)
    self.rect = pygame.Rect(self.X,self.Y,25,25)
    self.speed = SPEED_ENEMY
    self.clock = pygame.time.Clock()
    self.xis=1
    self.yps=1

当测试碰撞时,这两种方法返回一些东西(对我来说已经很棒了,因为还有其他尝试只返回错误)但是即使我碰到游戏时它们总是返回0。 当玩家(通过按键输入控制)接触敌人的精灵图像(通过舞台随机移动)时,应该发生碰撞。

这些是我的测试方法:

print pygame.sprite.collide_rect(player, enemy),pygame.sprite.collide_rect(player, enemy2)
print pygame.sprite.collide_rect(player, enemy),player.rect.colliderect(enemy2)
print player.rect.colliderect(enemy),player.rect.colliderect(enemy2)

(编辑) 我一直致力于显示更多代码,以便找到问题,所以就是这样 (我也将全局加载精灵,将它们作为参数传递给对象,尖端的坦克)。

玩家对象:

# -*- coding: cp1252 -*-
import pygame, os
from pygame.locals import *
from Configs import *
from random import randint

class dude(pygame.sprite.Sprite):
def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = self.load_image(SPRITE_PLAYER)
    self.X = randint(34,ALTURA-10)
    self.Y = randint(34,LARGURA-10)
    self.rectBox()
    self.speed = SPEED_PLAYER
    self.clock = pygame.time.Clock()

def load_image(self,image_loaded):
    try:
        image = pygame.image.load(image_loaded)
    except pygame.error, message:
        print "Impossivel carregar imagem: " + image_loaded
        raise SystemExit, message
    return image.convert_alpha()

def rectBox(self):
    self.rect = self.image.get_rect()
    self.image_w, self.image_h  = self.image.get_size()
    self.rect.move(self.X, self.Y)          
    self.rect.topleft = (self.X, self.Y)
    self.rect.bottomright = (self.X + self.image_w, self.Y + self.image_h)

def update(self,xis,yps,screen):
    time_passed = self.clock.tick()
    time_passed_seconds = time_passed/1000.0
    distance_moved = time_passed_seconds * (self.speed +100) #Distancia = tempo * velocidade

    self.X +=xis*distance_moved
    self.Y +=yps*distance_moved

    screen.blit(self.image, (self.X,self.Y))

    if self.X>ALTURA-52:
        self.X-=2

    elif self.X<30:
        self.X+=2

    if self.Y>LARGURA-52:
        self.Y-=2

    elif self.Y<30:
        self.Y+=2

敌人对象:

# -*- coding: cp1252 -*-
import pygame, os
from pygame.locals import *
from Configs import *
from random import randint

class enemy(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = self.load_image(SPRITE_ENEMY)
        self.X = randint(34,ALTURA-10)
        self.Y = randint(34,LARGURA-10)
        self.rectBox()
        self.speed = SPEED_ENEMY
        self.clock = pygame.time.Clock()
        self.xis=1
        self.yps=1

    def load_image(self,image_loaded):
        try:
            image = pygame.image.load(image_loaded)
        except pygame.error, message:
            print "Impossivel carregar imagem: " + image_loaded
            raise SystemExit, message
        return image.convert_alpha()

    def rectBox(self):
        self.rect = self.image.get_rect()
        self.image_w, self.image_h  = self.image.get_size()
        self.rect.move(self.X, self.Y)          
        self.rect.topleft = (self.X, self.Y)
        self.rect.bottomright = (self.X + self.image_w, self.Y + self.image_h)

    def update(self,screen):
        time_passed = self.clock.tick()
        time_passed_seconds = time_passed/1000.0
        distance_moved = time_passed_seconds * (self.speed +100)

        self.X +=self.xis*distance_moved
        self.Y -=self.yps*distance_moved

        screen.blit(self.image, (self.X,self.Y))

        #Maquina de estados finitos para inteligência da movimentação
        if self.X>ALTURA-50:
            self.X-=2
            self.xis=-1
        elif self.X<30:
            self.X+=2
            self.xis=1

        if self.Y>LARGURA-50:
            self.Y-=2
            self.yps=1
        elif self.Y<30:
            self.Y+=2
            self.yps=-1

主要剧本:

# -*- coding: cp1252 -*-
import pygame, os
from pygame.locals import *
from Configs import *
from Enemy import enemy as e
from Player import dude
from sys import exit

pygame.init()

#Função para carregar imagens
def load_image(image_loaded):
        try:
            image = pygame.image.load(image_loaded)
        except pygame.error, message:
            print "Impossivel carregar imagem: " + image_loaded
            raise SystemExit, message
        return image.convert()

#Funções do Pause
def pause():
    drawpause()
    while 1:
        p = pygame.event.wait()
        if p.type in (pygame.QUIT, pygame.KEYDOWN):
            return

def drawpause():
    font = pygame.font.Font(None, 48)
    text1 = font.render("PAUSE", 1, (10, 10, 10))
    text1pos = text1.get_rect()
    text1pos.centerx = screen.get_rect().centerx
    text1pos.centery = screen.get_rect().centery
    screen.blit(text1, text1pos)
    font = pygame.font.Font(None, 36)
    text2 = font.render("Pressione qualquer tecla para continuar", 1, (10, 10, 10))
    text2pos = text2.get_rect()
    text2pos.centerx = screen.get_rect().centerx
    text2pos.centery = screen.get_rect().centery + 50
    screen.blit(text2, text2pos)
    pygame.display.flip()

#Inicializa tela principal    
os.environ["SDL_VIDEO_CENTERED"] = "1"
screen = pygame.display.set_mode((ALTURA, LARGURA),0,32)
bg = load_image(BACKGROUND)
pygame.display.set_caption("Jogo teste para TCC - Top-Down")

#Inicialização do personagem
move_x, move_y = 0, 0
player = dude()

#Inicialização dos inimigos
enemy = e()
enemy2 = e()

#Atribuição de grupos de entidades
inimigos = pygame.sprite.Group()
inimigos.add(enemy)
inimigos.add(enemy2)

personagem = pygame.sprite.Group()
personagem.add(player)

#Objeto clock
clock = pygame.time.Clock()

#Loop principal sprite.get_height() sprite.get_width()
while True:

    #Eventos do jogo
    for event in pygame.event.get():
        #SAIR DO JOGO
        if event.type == QUIT:
            pygame.quit()
            exit()
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                exit()
            elif event.key == K_p:
                pause()

        #TECLAS DE MOVIMENTAÇÃO PERSONAGEM
        if event.type == KEYDOWN:
            if event.key == K_LEFT:
                move_x = -1
            elif event.key == K_RIGHT:
                move_x = +1
            elif event.key == K_UP:
                move_y = -1
            elif event.key == K_DOWN:
                move_y = +1
        elif event.type == KEYUP:
            if event.key == K_LEFT:
                move_x = 0
            elif event.key == K_RIGHT:
                move_x = 0
            elif event.key == K_UP:
                move_y = 0
            elif event.key == K_DOWN:
                move_y = 0

    #Posicionamento do background
    screen.blit(bg, (0,0))

    #Movimentação do personagem
    player.update(move_x,move_y,screen)

    #Movimentação inimigos
    enemy.update(screen)
    enemy2.update(screen)

    #Teste colisão
    #print pygame.sprite.collide_rect(player, enemy),pygame.sprite.collide_rect(player, enemy2)
    #print pygame.sprite.collide_rect(player, enemy),player.rect.colliderect(enemy2)
    #print player.rect.colliderect(enemy),player.rect.colliderect(enemy2)

    #Refresh (por FPS)
    pygame.display.update()

多数民众赞成,感谢我对帖子的反馈!

1 个答案:

答案 0 :(得分:0)

如果您遇到碰撞检测问题,打印精灵的rect通常会有帮助,例如: print(player.rect)。它会向您显示rects永远不会更新,并且它们保持在同一位置,并且因为它们被用于碰撞检测,所以您的精灵不会碰撞。

要解决您的问题,您必须将精灵的self.rect.center(或self.rect.topleft)设置为self.X中的当前self.Yupdate坐标方法

self.rect.center = self.X, self.Y

我建议您查看pygame.sprite.spritecollide方法。将你的敌人放入一个单独的精灵组中,然后以这种方式获得碰撞的精灵:

collided_enemies = pg.sprite.spritecollide(player, enemies, False)
for collided_enemy in collided_enemies:
    # Do something with the collided_enemy.

这是一个简单,完整的例子:

import sys
import pygame as pg


class Player(pg.sprite.Sprite):

    def __init__(self, pos, color):
        super().__init__()
        self.image = pg.Surface((50, 30))
        self.image.fill(color)
        self.rect = self.image.get_rect(center=pos)


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    player = Player((100, 100), pg.Color('dodgerblue2'))
    enemy = Player((300, 100), pg.Color('sienna2'))
    enemy2 = Player((200, 300), pg.Color('sienna2'))
    all_sprites = pg.sprite.Group(player, enemy, enemy2)
    enemies = pg.sprite.Group(enemy, enemy2)

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            if event.type == pg.MOUSEMOTION:
                player.rect.center = event.pos

        all_sprites.update()

        collided_enemies = pg.sprite.spritecollide(player, enemies, False)
        for collided_enemy in collided_enemies:
            print(collided_enemy.rect)

        screen.fill((50, 50, 50))
        all_sprites.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()