I'm having some trouble figuring out how I can handle collisions that are specifically colliding on the top or bottom a rect. How can specify those collisions?

Here's a little code snippet to give you an idea of my approach. As it is now it doesn't matter where it collides.

# the ball has hit one of the paddles. send it back in another direction.
    if paddleRect.colliderect(ballRect) or paddle2Rect.colliderect(ballRect):
        if directionOfBall == 'upleft':
            directionOfBall = 'upright'
        elif directionOfBall == 'upright':
            directionOfBall = 'upleft'
        elif directionOfBall == 'downleft':
            directionOfBall = 'downright'
        elif directionOfBall == 'downright':
            directionOfBall = 'downleft'

Thanks in advance.


Paddle rect:

|    |
|    |
|    | Sides
|    |

I need to know if the ball has hit either the top or the bottom.

  • 1
    \$\begingroup\$ possible duplicate of 2d Collision detecton axis aligned boxes \$\endgroup\$ Sep 3 '13 at 20:56
  • \$\begingroup\$ When two rects are overlapping there is no directionality to their state of collision, they are just ... colliding ... Do you mean if you have two rects that are moving, how to tell whether or not they collided against a given edge? \$\endgroup\$
    – Mokosha
    Sep 4 '13 at 0:46
  • \$\begingroup\$ @sean No. It's not a duplicate. My question is about Pygame specifically, I'm not making a physics engine myself. \$\endgroup\$
    – Chakotay
    Sep 5 '13 at 15:23
  • \$\begingroup\$ @Mokosha Well they are moving...but I need to know if the one rect (the ball) has collided with the other rect's (the paddle) top or botom. Look at my edit above. \$\endgroup\$
    – Chakotay
    Sep 5 '13 at 15:24

Makeup of angles:

Basically you have to look at the angles between the center of the rectangle you are using for a paddle and the center of the rectangle of the ball (can also be a point since we collapse the ball rectangle into a point anyways).

enter image description here

The angle between the center points is then compared to the quadrants given by the corner points of the paddle (this gives left, right, up, down). The following program does just that with a bit of normalization to make lookup in the array easier.

Test program

The part relevant to your question is really the DirRect class.

import pygame
import math

class DirRect(pygame.Rect):
    def direction_to_rect(self, drect):
        ar = math.atan2(self.centery - self.top, self.right - self.centerx) # half of the angle of the right side
        # construct the corner angles into an array to search for index such that the index indicates direction
        # this is normalized into [0, 2π] to make searches easier (no negative numbers and stuff) 
        dirint = [ 2*ar, math.pi, math.pi+2*ar, 2*math.pi]
        # calculate angle towars the center of the other rectangle, + ar for normalization into
        ad = math.atan2(self.centery - drect.centery, drect.centerx - self.centerx) + ar
        # again normalization, sincen atan2 ouputs values in the range of [-π,π]
        if ad < 0:
            ad = 2*math.pi + ad
        # search for the quadrant we are in and return it
        for i in xrange(len(dirint)):
            if ad < dirint[i]:
                return i
        # just in case -1 as error indicator
        return -1

screen = pygame.display.set_mode([400,400])

# This is the paddle
paddle = DirRect( (150,150),(40,20) )
# colorize directional information
colors = [ (255,0,0), #right
           (0,255,0), #up
           (0,0,255), #left
           (0,0,0), #down
           (255,255,255) # error = -1

#show direction for every point
dsurf = pygame.display.get_surface()
for x in xrange(dsurf.get_width()):
    for y in xrange(dsurf.get_height()):
        prect = pygame.Rect((x,y),(0,0))
        dsurf.set_at( (x,y), colors[paddle.direction_to_rect(prect)])
#show paddle
pygame.draw.rect( dsurf, (128,128,128), paddle, 1)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
def on_collide(paddle, ball):
    # we collided, so which side? Args are the `Rect`s of paddle and ball.
    if paddle.centery < ball.centery:   
        print("paddle bottom")
    elif paddle.centery > ball.centery:
        print("paddle top")

    if paddle.centerx < ball.centerx:
        print("paddle right")
    elif paddle.centerx > ball.centerx:
        print("paddle left")
  • \$\begingroup\$ That looks like a great answer, although I have not had the chance to try it yet. But can pygame do print statements? \$\endgroup\$
    – Chakotay
    Oct 30 '13 at 23:11
  • \$\begingroup\$ Yep, you can have a standard console open with pygame. Or you can replace them with your actions there. \$\endgroup\$
    – monkey
    Oct 31 '13 at 1:37
  • \$\begingroup\$ this is quiet simple but really what I was looking for \$\endgroup\$
    – xhallix
    Jan 2 '15 at 8:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.