pygame 中的碰撞检测
Collision detection in pygame
我写了一个小测试来感受一下 pygame 中的碰撞检测。我的球员正确移动并停在岩石处,碰撞将发生在那里,但当我到达岩石时我无法再次移动。大家知道为什么会这样吗?这是我的测试代码:
import pygame
import sys
white = (255, 255, 255)
black = ( 0, 0, 0)
# Player class
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('../foo.png')
self.rect = self.image.get_rect()
class Rock(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('../rock.png')
self.rect = self.image.get_rect()
self.rect.x = 50
self.rect.y = 50
# essential pygame init
pygame.init()
# screen
screen_width = 400
screen_height = 400
screen_size = (screen_width, screen_height)
screen = pygame.display.set_mode(screen_size)
# List for all sprites
sprites = pygame.sprite.Group()
# Rock
rock = Rock()
sprites.add(rock)
# Create player
player = Player()
sprites.add(player)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
sys.exit()
sprites.update()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT] and not player.rect.colliderect(rock.rect):
#if not player.rect.colliderect(rock.rect):
move = (-1, 0)
player.rect = player.rect.move(move)
if pressed[pygame.K_RIGHT] and not player.rect.colliderect(rock.rect):
move = (1, 0)
player.rect = player.rect.move(move)
if pressed[pygame.K_UP] and not player.rect.colliderect(rock.rect):
move = (0, -1)
player.rect = player.rect.move(move)
if pressed[pygame.K_DOWN] and not player.rect.colliderect(rock.rect):
move = (0, 1)
player.rect = player.rect.move(move)
screen.fill(white)
sprites.draw(screen)
pygame.display.flip()
clock.tick(30)
pygame.quit()
编辑:当我将移动速度降低到 1 时,玩家仍然卡在岩石中。我也更新了代码。
如果你的石头不在5个单位边界,你可以移动"into"石头,然后被卡住。
你的答案包含在你的问题中..
if .... . and not player.rect.colliderect(rock.rect):
你所有的移动键只有在不发生碰撞时才允许使用。
只要您在碰撞范围内,就允许 none 的移动动作。
你必须允许远离障碍物的移动键!
为此,您需要知道碰撞发生的位置。
(在字符前面,字符左侧等。)
编辑:灵感来自另一个答案
在答案被接受后,此编辑被包含在内;)
原因是解决方案比检查碰撞方向更好,因为它不需要你计算任何东西..
这个想法很简单..
总是尝试移动,只有当结果不会导致碰撞时,才应用它。
这将始终允许合法移动,并且不会让您卡住。
唯一需要注意的是,如果一个移动步长大于障碍步长,那么非常小的障碍可能 "jumped"..
Simple and working way to check collision is to move first, check for
collision and move back if necessary.
和这条评论:
move returns a new Rect, so you can use that to check for an collision. If there is one, do nothing. If there is no collision, set player.rect to the new rect or (call move_ip on player.rect).
你检查你没有碰撞然后移动。想象一下,您在岩石下方 1 个单位,然后向上移动 1 个单位。您可以这样做,因为您 现在 没有被卡住。但是现在你在岩石中而且你不能移动。
检查碰撞的简单有效方法是先移动,检查碰撞并在必要时向后移动。
我写了一个小测试来感受一下 pygame 中的碰撞检测。我的球员正确移动并停在岩石处,碰撞将发生在那里,但当我到达岩石时我无法再次移动。大家知道为什么会这样吗?这是我的测试代码:
import pygame
import sys
white = (255, 255, 255)
black = ( 0, 0, 0)
# Player class
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('../foo.png')
self.rect = self.image.get_rect()
class Rock(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('../rock.png')
self.rect = self.image.get_rect()
self.rect.x = 50
self.rect.y = 50
# essential pygame init
pygame.init()
# screen
screen_width = 400
screen_height = 400
screen_size = (screen_width, screen_height)
screen = pygame.display.set_mode(screen_size)
# List for all sprites
sprites = pygame.sprite.Group()
# Rock
rock = Rock()
sprites.add(rock)
# Create player
player = Player()
sprites.add(player)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
sys.exit()
sprites.update()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT] and not player.rect.colliderect(rock.rect):
#if not player.rect.colliderect(rock.rect):
move = (-1, 0)
player.rect = player.rect.move(move)
if pressed[pygame.K_RIGHT] and not player.rect.colliderect(rock.rect):
move = (1, 0)
player.rect = player.rect.move(move)
if pressed[pygame.K_UP] and not player.rect.colliderect(rock.rect):
move = (0, -1)
player.rect = player.rect.move(move)
if pressed[pygame.K_DOWN] and not player.rect.colliderect(rock.rect):
move = (0, 1)
player.rect = player.rect.move(move)
screen.fill(white)
sprites.draw(screen)
pygame.display.flip()
clock.tick(30)
pygame.quit()
编辑:当我将移动速度降低到 1 时,玩家仍然卡在岩石中。我也更新了代码。
如果你的石头不在5个单位边界,你可以移动"into"石头,然后被卡住。
你的答案包含在你的问题中..
if .... . and not player.rect.colliderect(rock.rect):
你所有的移动键只有在不发生碰撞时才允许使用。 只要您在碰撞范围内,就允许 none 的移动动作。
你必须允许远离障碍物的移动键! 为此,您需要知道碰撞发生的位置。 (在字符前面,字符左侧等。)
编辑:灵感来自另一个答案
在答案被接受后,此编辑被包含在内;) 原因是解决方案比检查碰撞方向更好,因为它不需要你计算任何东西..
这个想法很简单.. 总是尝试移动,只有当结果不会导致碰撞时,才应用它。
这将始终允许合法移动,并且不会让您卡住。
唯一需要注意的是,如果一个移动步长大于障碍步长,那么非常小的障碍可能 "jumped"..
Simple and working way to check collision is to move first, check for collision and move back if necessary.
和这条评论:
move returns a new Rect, so you can use that to check for an collision. If there is one, do nothing. If there is no collision, set player.rect to the new rect or (call move_ip on player.rect).
你检查你没有碰撞然后移动。想象一下,您在岩石下方 1 个单位,然后向上移动 1 个单位。您可以这样做,因为您 现在 没有被卡住。但是现在你在岩石中而且你不能移动。
检查碰撞的简单有效方法是先移动,检查碰撞并在必要时向后移动。