Search code examples
pythonpygamegeometryanglebounce

Angle Reflexion for bouncing ball in a circle


I am making a game with some bouncing elements IN a circle (I use pygame) , My elements have 2 attributes , one for the angle and one for the speed Here is how elements moves :

mvx = math.sin(self.angle) * self.speed  
mvy = -math.cos(self.angle) * self.speed  
self.x += mvx  
self.y += mvy

My problem is this : I know the angle at the top (99.6°) , I have the collision point (x and y ) , but I'm unable to find the angle at the bottom(42.27°) Does someones can make a relation between the first angle and the second ?

Picture is better ...


Solution

  • I recommend do calculate the reflection vector to the incident vector on the circular surface.
    In the following formula N is the normal vector of the circle, I is the incident vector (the current direction vector of the bouncing ball) and R is the reflection vector (outgoing direction vector of the bouncing ball):

    R = I - 2.0 * dot(N, I) * N.
    

    Use the pygame.math.Vector2.

    To calculate the normal vector, you' ve to know the "hit" point (dvx, dvy) and the center point of the circle (cptx, cpty):

    circN = (pygame.math.Vector2(cptx - px, cpty - py)).normalize()
    

    Calculate the reflection:

    vecR = vecI - 2 * circN.dot(vecI) * circN
    

    The new angle can be calculated by math.atan2(y, x):

    self.angle  = math.atan2(vecR[1], vecR[0])
    

    Code listing:

    import math
    import pygame
    
    px = [...] # x coordinate of the "hit" point on the circle
    py = [...] # y coordinate of the "hit" point on the circle
    
    cptx = [...] # x coordinate of the center point of the circle
    cpty = [...] # y coordinate of the center point of the circle
    
    circN = (pygame.math.Vector2(cptx - px, cpty - py)).normalize()
    vecI  = pygame.math.Vector2(math.cos(self.angle), math.sin(self.angle))
    vecR  = vecI - 2 * circN.dot(vecI) * circN
    
    self.angle = math.pi + math.atan2(vecR[1], vecR[0])