0

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

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()
4

1 回答 1

3

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

如果您阅读pygame.sprite.collide_mask的文档,您会注意到它说您的精灵需要具有maskrect属性。您的 sprite 中有 arect并将其设置在 中__init__(),但是当您移动 sprite 时不会保持更新。您只需更改xandy属性而不调整rect位置。collide_mask想要 a的原因rect是它使用它来确定它使用的pygame.mask.Mask.overlap()调用的offset参数。重要的是要意识到掩码本身没有位置,它们需要s 来确定掩码的相对位置。rect

这类似于没有位置并且需要rect为它们跟踪的图像/表面。

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

于 2020-08-05T04:07:51.897 回答