Pygame 像素完美碰撞未按预期工作

Pygame pixel perfect collision not working as expected

我正在使用 pygame 创建俄罗斯方块。我想使用碰撞检测,以便当游戏中的形状与之前播放的任何其他形状接触时,我可以按照俄罗斯方块的逻辑停止该形状。我遇到了使用蒙版的像素完美碰撞。我已经在线学习了一些教程,但是每次出现新形状时像素检测 returns 为真,而不是任何形状发生碰撞时。对于长代码提前抱歉,它是代码实际并且仍然包含它的游戏元素的最低限度。我认为我的方法有问题导致了这个错误。我基本上有一个功能,每当游戏中的形状与 'floor' 接触时,该形状就会保持在该位置并创建一个新形状。我认为我把它复杂化了,反过来又造成了这个错误。提前致谢

import pygame
import sys
import shapelogic

pygame.init()

screensize = width, height = 800, 595

screen = pygame.display.set_mode(screensize)



background_image =pygame.image.load("/Users/marceason/PycharmProjects/Tetris/Wooden_background.jpg").convert_alpha()

myshape = 0
stop_movement = 0
blit_count = 0
stored_shapes = pygame.sprite.Group()
stored_shapes_with_coords = []
extra_blit_required = False


index = 0
count = 0
listofshapes = []

class shapemanager():

    def __init__(self):

        self.listofshapes = []


    def create_another_instance(self):

        global count
        count += 1
        string = "Shape_{0},".format(count)

        another_shape = Shape(string)
        self.listofshapes.append(another_shape)
        global index
        object = self.listofshapes[index]
        index += 1
        return object


def load_shape(self):
    shape = self.create_another_instance()
    shape.load_shapes()







class Shape(pygame.sprite.Sprite):

def __init__(self, name):
    pygame.sprite.Sprite.__init__(self)

    self.name = name
    self.x = 50
    self.y = 100
    self.move_event = pygame.USEREVENT + 1
    self.reached_bottom_event = pygame.USEREVENT + 2
    self.one_sec_timer = 1000
    self.half_sec_timer = 500

    self.reachbottomflag = False
    self.movement_possible = True

    self.image = pygame.image.load(
"/Users/marceason/PycharmProjects/Tetris/Tetris_Shapes/Green_Shape_1_Position_1.png")
    self.mask = pygame.mask.from_surface(self.image)
    self.rect = self.image.get_rect()


def move_shape(self):
    if self.movement_possible:
        key_input = pygame.key.get_pressed()
        if key_input[pygame.K_LEFT]:
            self.x -= 16
        if key_input[pygame.K_RIGHT]:
            self.x += 16
        if not self.reachbottomflag:
            if key_input[pygame.K_DOWN]:
                self.y += 16


def reachbottom(self):

    if self.y >= 560:
        self.reachbottomflag = True

def no_movement_possible(self):

    self.movement_possible = False





def assign_shape():

global myshape
global stop_movement
myshape = sl.create_another_instance()
pygame.time.set_timer(myshape.move_event, myshape.one_sec_timer)
stop_movement = pygame.time.set_timer(myshape.reached_bottom_event, myshape.half_sec_timer)


def blit_used_shapes():

global screen
global blit_count
blit_count = len(stored_shapes_with_coords)
local_count = 0
while local_count < blit_count:
    screen.blit(stored_shapes_with_coords[local_count][0], (stored_shapes_with_coords[local_count][1], stored_shapes_with_coords[local_count][2]))
    local_count += 1


sl = shapemanager()





##### HERE IS THE PIXEL DETECTION #####
result = pygame.sprite.spritecollide(myshape, stored_shapes, False, pygame.sprite.collide_mask)


## Main loop ##

assign_shape()

while True:

for event in pygame.event.get():
    if event.type == pygame.QUIT: sys.exit()
    screen.blit(background_image, (0, 0))
    screen.blit(myshape.image, (myshape.x, myshape.y))
    myshape.move_shape()



    key_input = pygame.key.get_pressed()
    if key_input[pygame.K_SPACE]:
        myshape.rotate_shape()


    myshape.reachbottom()
    if myshape.reachbottomflag:
        if event.type == myshape.reached_bottom_event:
            myshape.no_movement_possible()
            stored_shape_tuple = [myshape.image, myshape.x, myshape.y]
            stored_shapes_with_coords.append(stored_shape_tuple)
            stored_shapes.add(myshape)

            extra_blit_required = True

            assign_shape()
            ####### PIXEL DETECTION IS HERE IN FOR LOOP ####
            if result:
                print("this should only execute when two shapes touch!!")

    if extra_blit_required:
        blit_used_shapes()

    pygame.display.update()

问题是您没有更新精灵 rect 属性。精灵 rect 都具有位置 (0, 0)(因为您没有在对 self.image.get_rect() 的调用中设置它)因此蒙版将全部重叠和碰撞。

如果您阅读了它使用的 pygame.sprite.collide_mask you will note that it says that your sprites need to have mask and rect attributes. You have a rect in your sprite and you set it in the __init__(), but you do not keep it updated when you move the sprite. You just change the x and y attributes without adjusting the rect position. The reason that the collide_mask wants a rect is that it uses that to determine the offset parameter for the pygame.mask.Mask.overlap() 调用的文档。重要的是要意识到面具本身没有位置,他们需要 rects 来确定面具的相对位置。

这类似于 images/surfaces 没有位置并需要 rect 来为他们跟踪。

在一个单独的问题上,您将 sprite 传送到屏幕的方式毫无意义。您没有使用 sprite 组的能力进行绘制,更糟糕的是,您将 sprite 的图像、x 和 y 保存在单独的列表中,而不将其包含在 sprite 本身中。您应该查看一些基于 pygame 精灵的代码示例。那里有很多例子。