【问题标题】:Collision Detection without Coordinates in Tilemaps in PygamePygame中Tilemaps中没有坐标的碰撞检测
【发布时间】:2020-08-25 09:47:40
【问题描述】:

我正在编写一个炸弹人游戏,现在我没有任何精灵,但我使用矩形。 这是我的代码:

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, p1y, 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, 32))


class Breakable:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        pygame.draw.rect(win, (200, 150, 100), (x, y, 32, 32))


game_map1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 10, 10, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 10, 10, 0],
             [0, 10, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2, 0, 10, 0],
             [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
             [0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
             [0, 2, 2, 2, 2, 10, 10, 2, 2, 10, 2, 2, 10, 10, 2, 2, 2, 2, 0],
             [0, 2, 0, 2, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 2, 0, 2, 0],
             [0, 2, 2, 2, 2, 2, 0, 2, 2, 10, 2, 2, 0, 2, 2, 2, 2, 2, 0],
             [0, 2, 0, 2, 0, 2, 0, 2, 10, 10, 10, 2, 0, 2, 0, 2, 0, 2, 0],
             [0, 0, 0, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 0, 0, 0],
             [0, 2, 0, 2, 0, 2, 0, 2, 10, 10, 10, 2, 0, 2, 0, 2, 0, 2, 0],
             [0, 2, 2, 2, 2, 2, 0, 2, 2, 10, 2, 2, 0, 2, 2, 2, 2, 2, 0],
             [0, 2, 0, 2, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 2, 0, 2, 0],
             [0, 2, 2, 2, 2, 10, 10, 2, 2, 10, 2, 2, 10, 10, 2, 2, 2, 2, 0],
             [0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
             [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
             [0, 10, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2, 0, 10, 0],
             [0, 10, 10, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 10, 10, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, tlw, tlh)
            if tile == 10:
                pygame.Rect(x * 32, y * 32, 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

The Wall 和 Breakable 也在使用 tlwtlh,而且它们没有玩家拥有的特定坐标。

sooo... 我看了一个教程 (https://www.youtube.com/watch?v=HCWI2f7tQnY&t=2s),甚至尝试自己进行碰撞检测。但我就是做不到。我没有瓷砖地图中矩形的坐标,瓷砖地图中也有很多矩形。你怎么能用一个没有坐标和很多矩形的tilemap进行碰撞检测?是的,游戏目前没有太多内容......我用pygame.Rect的player_rectwall_rect尝试了它,然后使用(colliderect),但它没有用,你怎么能做如果 player_rect 与所有 wall_rect 碰撞,而不仅仅是一个。

我的问题是:如何使用 colliderect 对 tilemaps 进行碰撞检测?

【问题讨论】:

    标签: python pygame coordinates collision-detection


    【解决方案1】:

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

    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, 32))
    
        def getRect(self):
            return pygame.Rect(self.x, self.y, 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, self.y, 32, 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), self.rect)
    
        def getRect(self):
            return pygame.Rect(self.x, self.y, 32, 32)
    
    
    game_map1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 10, 10, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 10, 10, 0],
                 [0, 10, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2, 0, 10, 0],
                 [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
                 [0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
                 [0, 2, 2, 2, 2, 10, 10, 2, 2, 10, 2, 2, 10, 10, 2, 2, 2, 2, 0],
                 [0, 2, 0, 2, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 2, 0, 2, 0],
                 [0, 2, 2, 2, 2, 2, 0, 2, 2, 10, 2, 2, 0, 2, 2, 2, 2, 2, 0],
                 [0, 2, 0, 2, 0, 2, 0, 2, 10, 10, 10, 2, 0, 2, 0, 2, 0, 2, 0],
                 [0, 0, 0, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 0, 0, 0],
                 [0, 2, 0, 2, 0, 2, 0, 2, 10, 10, 10, 2, 0, 2, 0, 2, 0, 2, 0],
                 [0, 2, 2, 2, 2, 2, 0, 2, 2, 10, 2, 2, 0, 2, 2, 2, 2, 2, 0],
                 [0, 2, 0, 2, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 2, 0, 2, 0],
                 [0, 2, 2, 2, 2, 10, 10, 2, 2, 10, 2, 2, 10, 10, 2, 2, 2, 2, 0],
                 [0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
                 [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
                 [0, 10, 0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 2, 0, 2, 0, 10, 0],
                 [0, 10, 10, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 10, 10, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 32])))
            if tile == 10:
                pass
            if tile == 2:
                walls.append(Breakable(pygame.Rect([x*32, y*32, 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()
    

    关于你的最后一个问题:

    #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
    

    这些是您可以使用的自定义碰撞检测功能。我没有播放器左侧的那个(rect1),但我稍后会尝试制作它,或者您也可以尝试制作一个。您也可以尝试改进我提供的内容以适应您的游戏。使用这些,您可以准确地确定哪一方正在发生碰撞,并添加有用的逻辑。示例:

    #have different velocities for every side
    player_right_speed = 2
    player_left_speed = 2
    
    # Say that your player moves according to the following key presses
    key = pygame.key.get_pressed()
    if key[pygame.K_RIGHT]:
       playerx += player_right_speed
    if key[pygame.K_LEFT]:
       playerx -= player_left_speed
    
    #you can call the collision detection functions to check if they are colliding and if they are set the speed in that direction to 0
    #notice these functions take pygame.Rect as an argument
    right_colliding = rightCheck(playerRect, tileRect)
    if right_colliding:
       player_right_speed = 0
    left_colliding = leftCheck(playerRect, tileRect)
    if left_colliding:
       player_left_speed = 0
    

    【讨论】:

    • 好的...你能让我更清楚一点吗?我并不是说这很不清楚,但我是 pygame 的新手,我知道的不多,如果你看我已经有 wall_rect 和 player_rect
    • 对不起,但这不是我的实际问题。你怎么看我有碰撞。我会更新问题。很抱歉浪费您的时间。这是我的错
    • 所以碰撞起作用了,耶!但是嗯,瓷砖地图不再工作了......无论如何我们可以私下交谈,以便我可以向您展示我当前的代码?在告诉我之前,你有没有自己尝试过答案?
    • 您可以针对您的新问题提出另一个问题
    • 我不能。我被封后了。新的问题发生了,因为我做了你让我做的事。墙壁 = [] 和 wall.append() 部分
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-20
    • 2019-10-10
    相关资源
    最近更新 更多