UdayanS
UdayanS

Reputation: 43

How to detect the collision of circles or balls in Pygame?

I want to make a script in pygame where two balls fly towards each other and when they collide they should bounce off from each other but I don't know how to do this so can you help me?

Upvotes: -1

Views: 5365

Answers (2)

Rabbid76
Rabbid76

Reputation: 210889

To detect if 2 circles (respectively balls) are colliding, you've to test, if the Euclidean distance between the circles center points is less than the sum of the radii. I recommend to use pygame.math.Vector2 / distance_to() for the computation.
In the following the 1 circle is defined by the center point (x1, y1) and the radius r1. The 2nd circle is defined by (x2, y2) and r2:

v1 = pygame.math.Vector2(x1, y1)
v2 = pygame.math.Vector2(x2, y2)
if v1.distance_to(v2) < r1 + r2:
    print("hit")

If you have to test many collisions between circles you should compare the square of the distances to avoid the time consuming square root calculation necessary to calculate Euclidean distance. With distance_squared_to() there is also a function for this:

v1 = pygame.math.Vector2(x1, y1)
v2 = pygame.math.Vector2(x2, y2)
if v1.distance_squared_to(v2) < (r1 + r2)**2:
    print("hit")

If you want to make the circles bounce, you have to reflect the motion vector of the circle at the normal vector of the intersection like a billiard ball. Use pygame.math.Vector2 / reflect_ip() or reflect() to compute the new direction of the circle.
The movements of the circles are given by (mx1, my1) and (mx2, my2):

nv = v2 - v1
m1 = pygame.math.Vector2(mx1, my1).reflect(nv)
m2 = pygame.math.Vector2(mx2, my2).reflect(nv)
mx1, my1 = m1.x, m1.y
mx2, my2 = m2.x, m2.y

Minimal example: repl.it/@Rabbid76/PyGame-CirclesBounceOff

import pygame

pygame.init()

width, height = 400, 400
window = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()

x1, y1, r1, mx1, my1 = 200, 200, 50, 2, 0.5
x2, y2, r2, mx2, my2 = 300, 200, 50, -1, -1.5

def move(c, v, r, m):
    c += v
    if c < r: c, v = r, -v
    if c > m-r: c, v = m-r, -v   
    return c, v

hit_count = 0
run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    x1, mx1 = move(x1, mx1, r1, width)
    y1, my1 = move(y1, my1, r1, height)
    x2, mx2 = move(x2, mx2, r2, width)
    y2, my2 = move(y2, my2, r2, height)

    v1 = pygame.math.Vector2(x1, y1)
    v2 = pygame.math.Vector2(x2, y2)
    if v1.distance_to(v2) < r1 + r2 - 2:
        hit_count += 1
        print("hit:", hit_count)

        nv = v2 - v1
        m1 = pygame.math.Vector2(mx1, my1).reflect(nv)
        m2 = pygame.math.Vector2(mx2, my2).reflect(nv)
        mx1, my1 = m1.x, m1.y
        mx2, my2 = m2.x, m2.y

    window.fill((127, 127, 127))
    pygame.draw.circle(window, (255, 0, 0), (round(x1), round(y1)), r1, 4)
    pygame.draw.circle(window, (0, 0, 255), (round(x2), round(y2)), r2, 4)
    pygame.display.flip()

Upvotes: 6

VirtualSquares
VirtualSquares

Reputation: 125

Its pretty easy you just check if the x coordinate is in the same spot as the other x coordinate. For example if you had one of the x coordinated called x, and another one called i(there are 2 x coordinates for both of the balls) then you could just say if oh and before I say anything esle this example is fi your pygame window is a 500,500. You could say if x == 250: x -= 15. And the other way around for i. If i == 250: i += 15. Ther you go!. Obviously there are a few changes you have to do, but this is the basic code, and I think you would understand this

Upvotes: -2

Related Questions