问题
I wrote a little test to get a feeling for collision detection in pygame. My players moves properly and stop at the rock, where the collision shall happen, but when I reach the rock I can't move away again. Do you guys know why this is the case? This is my test code:
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()
Edit: When I lower the movement speed to 1, the player gets still stuck in the rock. I updated the code too.
回答1:
your answer is included in your question..
if .... . and not player.rect.colliderect(rock.rect):
all your movement keys are only allowed if not in collision. as soon as you are within collision range, none of your move actions are allowed.
you have to allow the movement key that moves away from the obstacle! to do that you need to know where the collision have occurred.. (in front of character, left of character etc..)
edit: inpsired from another answer
this edit was included, after the answer was accepted ;) the reason is that the solution is better, than checking the direction of the collision, as it doesn't require you to calculate anything..
The idea is simple.. always try to move, and only if the result doesn't result in collision, apply it.
that would always allow the legal movements, and won't get you stuck.
the only caveat is that very small obstacles could be "jumped" if one move step is larger that the obstacle step..
Simple and working way to check collision is to move first, check for collision and move back if necessary.
David Mašek
and this comment:
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).
sloth
回答2:
You check that you're not colliding and then move. Image you're 1 unit below rock and you move up 1 unit. You can do that because you're not stuck now. But now you're in the rock and you can't move.
Simple and working way to check collision is to move first, check for collision and move back if necessary.
回答3:
If your rock is not at at 5 unit boundary, you can move "into" the rock, and then are stuck.
来源:https://stackoverflow.com/questions/32266887/collision-detection-in-pygame