在Pygame的瓷砖地图中没有坐标的碰撞检测

问题描述

我正在编写Bomberman游戏,现在我没有任何精灵,但我使用矩形。 这是我的代码

import pygame

pygame.init()

WinWidth = 800
WinHeight = 608
p1x = 32
p1y = 32
vel = 1
clock = pygame.time.Clock()

win = pygame.display.set_mode((WinWidth,WinHeight))

def player():
    pygame.draw.rect(win,(0,200,200),(p1x,p1y,32,32))


player_rect = pygame.Rect(p1x,tlw,tlh)


class Wall:
    def __init__(self,x,y):
        self.x = x
        self.y = y
        pygame.draw.rect(win,(50,50,50),(x,y,32))


class Breakable:
    def __init__(self,(200,150,100),32))


game_map1 = [[0,0],[0,10,2,0]]

run = True
while run:

    pygame.init()

    clock.tick(100)
    win.fill((0,255,200))
    y = 0
    for layer in game_map1:
        x = 0
        for tile in layer:
            if tile == 0:
                Wall(x * 32,y * 32)
                wall_rect = pygame.Rect(x * 32,y * 32,tlh)
            if tile == 10:
                pygame.Rect(x * 32,32)
            if tile == 2:
                Breakable(x * 32,y * 32)
            x += 1
        y += 1

    player()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            run = False
        if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_d:
        if player_rect.colliderect(wall_rect):
            p1x *= -1
            p1y *= -1
        else:
            p1x += vel
    elif event.key == pygame.K_a:
        if player_rect.colliderect(wall_rect):
            p1x *= -1
            p1y *= -1
        else:
            p1x -= vel
    if event.key == pygame.K_s:
        if player_rect.colliderect(wall_rect):
            p1x *= -1
            p1y *= -1
        else:
            p1y += vel
    elif event.key == pygame.K_w:
        if player_rect.colliderect(wall_rect):
            p1x *= -1
            p1y *= -1
        else:
            p1y -= vel
        

    pygame.display.update()

xy在播放器矩形的左上方-它们分别是p1xp1y

宽度和高度分别为tlwtlh

Wall和Breakable也使用tlwtlh,它们没有播放器所具有的特定坐标。

如此...我看了一个教程(https://www.youtube.com/watch?v=HCWI2f7tQnY&t=2s),甚至试图自己进行碰撞检测。但是我做不到。我在tilemap中没有矩形的坐标,并且tilemap中也有很多矩形。如何使用无坐标且有多个矩形的图块进行碰撞检测?是的,该游戏目前还没有太多内容……我用pygame.Rect的player_rectwall_rect进行了尝试,然后使用了(colliderect),但没有工作,如何使player_rect与所有wall_rect碰撞,而不仅仅是与之碰撞。

我的问题是: 如何对碰撞发生的图块进行碰撞检测?

解决方法

我重构了整个代码,因为您发布的代码会引发错误,并且我无法测试我的代码。我们在这里实现冲突检测的方法是可行的,但并不是很有效。如果您想知道哪一方正在发生冲突,以便可以实施游戏逻辑,那么colliderect毫无意义。我建议您问一个有关如何构建自定义碰撞检测的新问题,因为它是一个全新的主题,但是以下代码解决了有关如何使用colliderect实现碰撞检测的原始问题。下面的示例还显示了draw函数应如何是一种单独的方法,这是更好的实现方法。顺便说一句,如果您将tile == 10放在您的问题中,而该问题基本上什么也没做,所以我将pygame.Rect(x * 32,y * 32,32,32)放在了问题中。如果希望将其用作新型墙,则可以创建类似于passBreakable的新类。最终答案,希望对您有所帮助:)。

Wall

关于您的最后一个问题:

import pygame

pygame.init()

WinWidth = 800
WinHeight = 608
clock = pygame.time.Clock()

win = pygame.display.set_mode((WinWidth,WinHeight))

class Player:
    def __init__(self):
        self.x = 32
        self.y = 32
        self.width = 20
        self.height = 20
        self.vel = 0.1

    def draw(self):
        pygame.draw.rect(win,(0,200,200),(self.x,self.y,32))

    def getRect(self):
        return pygame.Rect(self.x,self.width,self.height)


class Wall:
    def __init__(self,rect):
        self.rect =  rect
        self.x = rect.x
        self.y = rect.y
   
    def draw(self):
        pygame.draw.rect(win,(50,50,50),self.rect)

    def getRect(self):
        return pygame.Rect(self.x,32)


class Breakable:
    def __init__(self,rect):
        self.rect = rect
        self.x = rect.x
        self.y = rect.y

    def draw(self):
        pygame.draw.rect(win,(200,150,100),32)


game_map1 = [[0,0],[0,10,2,0]]


walls = []
y = 0
for layer in game_map1:
    x = 0
    for tile in layer:
        if tile == 0:
            walls.append(Wall(pygame.Rect([x*32,y*32,32])))
        if tile == 10:
            pass
        if tile == 2:
            walls.append(Breakable(pygame.Rect([x*32,32])))
        x += 1
    y += 1


player = Player()
pygame.init()
run = True
while run:

    clock.tick(100)
    win.fill((0,255,200))

    for i in range(len(walls)):
        walls[i].draw()

    player.draw()
        
    for wall in walls:
        if player.getRect().colliderect(wall.getRect()): #getRect is the method we added to wall class earlier
             print("they are colliding")    

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            run = False

        if event.type == pygame.KEYDOWN:
            for wall in walls:
                wall_rect = wall.getRect()
                if event.key == pygame.K_d:
                    if player.getRect().colliderect(wall_rect):
                        player.x *= -1
                        player.y *= -1
                    else:
                        player.x += player.vel
                elif event.key == pygame.K_a:
                    if player.getRect().colliderect(wall_rect):
                        player.x *= -1
                        player.y *= -1
                    else:
                        player.x -= player.vel
                if event.key == pygame.K_s:
                    if player.getRect().colliderect(wall_rect):
                        player.x *= -1
                        player.y *= -1
                    else:
                        player.y += player.vel
                elif event.key == pygame.K_w:
                    if player.getRect().colliderect(wall_rect):
                        player.x *= -1
                        player.y *= -1
                    else:
                        player.y -= player.vel
                    

    pygame.display.update()

这些是您可以使用的自定义冲突检测功能。我还没有一位球员(rect1)的左边,但我会稍后再尝试制作,或者您也可以尝试做成一位。您也可以尝试改进我提供的内容以适合您的游戏。使用这些,您可以准确地找出发生冲突的那一侧,并添加有用的逻辑。示例:

#Checks if right side of rect1 is colliding with left side of rect2
def rightCheck(rect1,rect2):
    if rect1.x + rect1.width > rect2.x:
        if (rect1.y > rect2.y and rect1.y < rect2.y + rect2.height) or (rect1.y + rect1.height < rect2.y + rect2.height and rect1.y + rect1.height> rect2.y):
            if rect1.x < rect2.x:
                return True
    return False

#Checks if top side of rect1 is colliding with bottom side of rect2
def topCheck(rect1,rect2):
    if rect1.y < rect2.y + rect2.height:
        if (rect1.x > rect2.x and rect1.x < rect2.x + rect2.width) or (rect1.x + rect1.width > rect2.x and rect1.x + rect1.width < rect2.x + rect2.width):
            if rect1.y > rect2.y:
                return True
    return False
 
#Checks if bottom side of rect1 is colliding with top side of rect2
def botCheck(rect1,rect2):
    if rect1.y + rect1.height > rect2.y:
        if (rect1.x > rect2.x and rect1.x < rect2.x + rect2.width) or (rect1.x + rect1.width > rect2.x and rect1.x + rect1.width < rect2.x + rect2.width):
            if rect1.y < rect2.y:
                return True
    return False