【问题标题】:How to add collisions between a player sprite (image) and a simple box如何在玩家精灵(图像)和简单盒子之间添加碰撞
【发布时间】:2015-08-09 07:30:46
【问题描述】:

我正在制作一个简单的马里奥游戏。我只是想要一个角色,显然马里奥会跳入一组碰撞框,这些碰撞框将显示一个数学问题的答案。到目前为止,我已经设法将重力和水平碰撞放在一起,但我似乎无法解决如何让我的角色在与简单的盒子/矩形碰撞时给我一个输出。到目前为止,这是我的代码:

import pygame
from block import *
from Player import *
pygame.mixer.pre_init(44100,  -16,  2,  2048)
pygame.init()
window = pygame.display.set_mode((800,  600))
pygame.display.set_caption("Super Mario Bros")
myfont = pygame.font.SysFont("Comic Sans MS", 100)
mariosound = pygame.mixer.music.load("data/sound.mp3")
pygame.mixer.music.play(-1)
gravity = -0.5
black = (0,  0,  0)
orange = (255,  174,  0)
blue = (11,  183,  217)
clock = pygame.time.Clock()
player = Player(0,  0)
label = myfont.render("9+10=", 1, black)

level1 = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
    [0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 1, 1]
]

def printText(txtText, Textfont, Textsize , Textx, Texty, Textcolor):
    myfont = pygame.font.SysFont(Textfont, Textsize)
    label = myfont.render(txtText, 1, Textcolor)
    window.blit(label, (Textx, Texty))
    pygame.display.flip()

blockList = []
for y in range(0,  len(level1)):
    for x in range(0,  len(level1[y])):
        if (level1[y][x]==1):
            blockList.append(Block(x*32,  y*32))

movex,  movey = 0, 0

gameLoop = True
while gameLoop:
    for event in pygame.event.get():
        if (event.type == pygame.QUIT):
            gameLoop = False
        if (event.type == pygame.KEYDOWN):
            if (event.key == pygame.K_RIGHT):
                movex = 5
            elif (event.key == pygame.K_LEFT):
                movex = -5
            elif (event.key == pygame.K_UP):
                player.jump()
        if (event.type == pygame.KEYUP):
             if (event.key == pygame.K_RIGHT):
                movex = 0
             elif (event.key == pygame.K_LEFT):
                movex = 0

    window.fill(blue)
    window.blit(label, (275, 100))
    for block in blockList:
        block.render(window)
    player.x += movex
    player.update(gravity,  blockList)
    player.render(window)
    clock.tick(60)
    pygame.display.flip()

pygame.quit()

我在不同的 python 文件中有一个播放器和碰撞子类,命名为:块和播放器,它只做碰撞和简单的重力等。

感谢您的帮助,正如我所说,我很新,所以任何解释或帮助将不胜感激。

这是我的其他代码: 我的播放器.py: 导入pygame

class Player:
    def __init__(self, x, y):
        self.x=x
        self.y=y
        self.width=32
        self.height=32
        self.velocity=0
        self.falling=True
        self.onGround=False

        self.images = pygame.image.load('resources/sprite.png')
        self.images = pygame.transform.scale(self.images, (35, 35))
    def jump(self):
        if (self.onGround == False):
            return
        self.velocity = 14
        self.onGround = False

    def detectCollisions(self, x1, y1, w1, h1, x2, y2, w2, h2):
        if (x2 + w2 > x1 >= x2 and y2 + h2 >= y1 >= y2):
            return True
        elif (x2 + w2 >= x1 + w1 > x2 and y2 + h2 >= y1 >= y2):
            return True
        elif (x2 + w2 >= x1 >= x2 and y2 + h2 >= y1 + h1 >= y2):
            return True
        elif (x2 + w2 >= x1 + w1 >= x2 and y2 + h2 >= y1 + h1 >= y2):
            return True
        else:
            return False

    def update(self, gravity, blockList):
        if (self.velocity < 0):
            self.falling = True
        collision = False
        blockX,blockY = 0,0
        for block in  blockList:
            collision = self.detectCollisions(self.x, self.y, self.width, self.height, block.x, block.y, block.width, block.height)
            if (collision == True):
                blockX=block.x
                blockY=block.y
                break
        if (collision == True):
            if (self.falling == True):
                self.falling = False
                self.onGround = True
                self.velocity = 0
                self.y = blockY - self.height

        if (self.onGround == False):
            self.velocity += gravity

        self.y-=self.velocity

    def render(self, window):
        window.blit(self.images, (self.x, self.y))

    def render1(self, collision):
        if (collision==True):
            pygame.draw.rect(window,red,(self.x,self.y,self.width,self.height))
        else:
            pygame.draw.rect(window,black,(self.x,self.y,self.width,self.height))

还有block.py: 导入pygame

class Block:
    def __init__(self, x, y):
        self.x=x
        self.y=y
        self.width=32
        self.height=32

    def render(self, window):
        pygame.draw.rect(window, (255,174,0),(self.x, self.y, self.width, self.height))

【问题讨论】:

  • 一个好的开始是停止使用xyheightwidth字段并改用简单的pygame.Rect,它提供了方便的方法,如colliderect , collidelist 等,您可以使用它们来代替您的 detectCollisions 方法。
  • 也许也看看这个question/answer。这是另一个主题,但有问题的代码使用了一种通用的碰撞检测技术(首先检查垂直轴,然后检查水平轴)。也许对你有帮助。
  • 谢谢 我去看看。

标签: python pygame sprite collision


【解决方案1】:

我不知道图片和盒子的尺寸,所以我写了一些随机尺寸。希望它会帮助你。 这是代码:

simplebox_width = 20 #pixels
simplebox_height = 20

image_width = 50
image_height = 250

image_x_coord = 100 #coords
image_y_coord = 200

simplebox_x_coord = 140
simplebox_y_coord = 250

image_x_side = range(image_x_coord, image_x_coord+image_width)
image_y_side = range(image_y_coord, image_y_coord+image_height)

simplebox_x_side = range(simplebox_x_coord, simplebox_x_coord+simplebox_width)
simplebox_y_side = range(simplebox_y_coord, simplebox_y_coord+simplebox_height)

for x in image_x_side:
    if x in simplebox_x_side:
        for y in image_y_side:
            if y in simplebox_y_side:
                collision = True
    else:
        collision = False

print collision

【讨论】:

  • 嘿利亚姆,谢谢你的回答。我对这一切还是很陌生。我应该重写碰撞类以响应您的代码吗?我只是对我目前正在做的事情感到困惑,如果可能的话,你能否简单地解释一下:) 干杯。
  • 你能告诉我究竟是什么让你感到困惑吗? @Doge
  • 首先,我已经有一个碰撞类和函数,用于阻止精灵/玩家从屏幕上掉下来。其次,我真的不明白我在这里做什么,我是在为现有的精灵分配一个矩形还是只是改变精灵的属性。除此之外,我有点困惑如何将所有这些联系在一起。
  • 用我的代码重写你的“detectcollision”函数
  • 很抱歉,我已经重启了多次,但似乎仍然无法弄清楚。每当我设置两个精灵时,一个是玩家,另一个是 pygame.draw.rect (矩形)它总是崩溃或给出错误。我很困惑:/