当前位置: 首页 > 知识库问答 >
问题:

PyGame中的雪碧碰撞测试(尝试:rect和group)

茹建茗
2023-03-14

我知道有将近5到6个类似于我正在做的问题,但是没有一个答案对我有帮助(如果我不是一个完全的新手,他们可能会帮助我),所以我会试着展示我的具体案例。

我试图在PyGame(Python lib)中做一个精灵碰撞测试,但是我不能让它工作,碰撞时我得到的都是“假”,它根本不起作用,我也不知道为什么,我已经连续搜索了两天。

在我的游戏中,我有对象玩家(我称之为“老兄”)和对象敌人(我称之为...“敌人”)。两者上的__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

当测试碰撞时,这两个方法返回一些东西(wich对我来说已经很棒了,因为还有其他尝试只返回错误),但即使在我碰撞时,它们也总是返回0。当玩家(由按键输入控制)触摸敌人的精灵ou图像(在舞台上随机移动)时,会发生碰撞。

以下是我的测试方法:

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个答案

巩俊远
2023-03-14

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

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

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()
 类似资料:
  • 我一直在学习一些pygame教程,并且基于这些教程开发了自己的代码。具体如下: 所以我想出了如何让我的家伙跳跃,但是我已经在天空中放置了一个块并试图这样做: 试图让角色停止跳跃。有没有一个内置的函数来测试这一点,或者有没有一个适合我的方法。顺便说一下,这是行不通的,我似乎也不知道该怎么做。非常感谢任何帮助:)

  • 我很难理解colliderect如何与精灵一起工作。我有一个很好的想法,但每当我尝试在游戏中实现它时,我只会收到错误消息“attributeError:'pygame.surface'对象没有属性'rect'” 基本上我所有的精灵都能工作(不包括ufo1),但是当我创建一个ufo1精灵的时候,它就崩溃了,我不知道如何修复它。 提前感谢。

  • 我正在做一个平台游戏,玩家有一把剑。我希望玩家只能在他下面有地面的时候攻击(所以他不能在空中攻击)。所以我实现了这段代码: 但是.. 每次返回零。虽然如果我将添加到测试玩家是否在地面的部分,它仍然存在!(虽然接地仍然等于零) 以下是完整的代码: 有人能帮忙吗?:)

  • 我有一个pygame精灵动画,其中精灵的位置和形状在整个特定的动画序列中发生变化(例如-攻击)。我如何为碰撞调整精灵的矩形? 我的图像:在动画的一部分中,我的精灵位于png图像文件的中心(96x64像素)。在动画的另一部分中,我的精灵靠近png图像文件的右侧(96x64像素)。在动画的另一部分中,精灵改变形状(由剑移动引起)。等等。 我是否必须进行一些数学运算和计算来调整动画每帧子画面的碰撞条件,

  • 所以我试图用Python和Pyplay创建一个益智平台游戏,但是我遇到了一点麻烦。当我为主要角色使用单点图像,而不是矩形图像时,如何制作碰撞检测器?我知道直角图像有左、右、顶部和底部像素功能(这对冲突检测非常有用),但是对于单片图像有这样的功能吗?或者我只需要为x和y坐标创建一个变量图像的宽度/高度?我试过用那个 但是catImg一直在通过窗户的尽头。我做错了什么?提前谢谢。

  • 在开始学习相关知识点之前,我们有必要先学习精灵和碰撞检测的含义。 精灵(英文译为 Sprite),其实在一个游戏程序中,精灵本质指的是一张张小尺寸的图片,比如游戏中的各种道具、人物、场景装饰等,它们都可以看做成一张张小的“精灵”图。除此之外,人物的移动也可以看做是一系列小精灵图构成的序列(按帧组成的序列),如下图所示: 图1:动作逐帧分解图 如果将逐帧分解后的动作,按照一定的频率播放,那么就形成了