Collision detection is a broad topic, especially if you want to know from which side a collection happened. (A common approach in plattformers is to do the collision detection twice, once for the horizontal and once for the vertical movement, like in this example).
If you just want to know if a Rect
collides with the bottom of another Rect
, the following example code should be a good starting point:
def collide_top(a, b):
return a.top <= b.bottom <= a.bottom and (a.left <= b.left <= a.right or b.left <= a.left <= b.right)
def collide_bottom(a, b):
return a.bottom >= b.top >= a.top and (a.left <= b.left <= a.right or b.left <= a.left <= b.right)
def collide_left(a, b):
return a.left <= b.right <= a.right and (a.top <= b.top <= a.bottom or b.top <= a.top <= b.bottom)
def collide_right(a, b):
return a.right >= b.left >= a.left and (a.top <= b.top <= a.bottom or b.top <= a.top <= b.bottom)
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
center = Rect((100, 100, 100, 100))
player = Rect((10, 0, 75, 75))
move = {K_UP: ( 0, -1),
K_DOWN: ( 0, 1),
K_LEFT: (-1, 0),
K_RIGHT: ( 1, 0)}
while True:
screen.fill((0, 0 ,0))
pressed = pygame.key.get_pressed()
for d in [m for (k, m) in move.items() if pressed[k]]:
player.move_ip(*d)
pygame.draw.rect(screen, (120, 0, 120), center, 3)
pygame.draw.rect(screen, (0, 200, 55), player, 2)
# check if 'player' collides with the bottom of 'center'
print collide_bottom(center, player)
pygame.display.flip()
if pygame.event.get(QUIT): break
pygame.event.poll()
clock.tick(60)
(In this picture, player
collides with the bottom and the left side of center
, but not with the top or right side)
Some further questions:
What happens when one rect is fully inside another one? Does it collide with all edges or none in this case?
In response to your comment:
You can simply change the collision check to
def collide_top(a, b):
return a.top == b.bottom and (a.left <= b.left <= a.right or b.left <= a.left <= b.right)
def collide_bottom(a, b):
return a.bottom == b.top and (a.left <= b.left <= a.right or b.left <= a.left <= b.right)
def collide_left(a, b):
return a.left == b.right and (a.top <= b.top <= a.bottom or b.top <= a.top <= b.bottom)
def collide_right(a, b):
return a.right == b.left and (a.top <= b.top <= a.bottom or b.top <= a.top <= b.bottom)