Question

This question requires no code, though it is an issue that I couldn't find the answer to elsewhere.

How might one test for collision of rects in Pygame only on an edge of the rect? I've looked at http://www.pygame.org/docs/ref/rect.html and feel like the answer's there, but that I just can't see it. This is very important, and I hope that this is an easy fix, and answerable.

if <rectname>.colliderect.bottom(<otherRect>):
    output = True

^ Does not work, but I suspect the answer might be similar. Thanks in advance if someone can help!

Was it helpful?

Solution

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)

enter image description here

(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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top