在 Pygame 的瓦片地图中没有坐标的碰撞检测



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

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

墙和易碎也使用tlwtlh,它们不像玩家那样有特定的坐标。

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

我的问题是:如何使用 colliderect 的瓦片地图进行碰撞检测?

我已经重构了整个代码,因为您发布的代码抛出错误并且我无法测试我的代码。我们在这里实现碰撞检测的方式有效,但并不真正有效。如果你想知道哪一方在碰撞,以便实现游戏逻辑,那么colliderect是毫无意义的。我建议您提出一个关于如何构建自定义碰撞检测的新问题,因为这是一个全新的主题,但以下代码解决了如何使用 colliderect 实现碰撞检测的原始问题。下面的示例还演示了绘制函数应如何成为单独的方法,这是更好的方法。顺便说一句,如果你tile == 10pygame.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

最新更新