Search code examples
pythonpygamegeometrygame-physics

Pygame - Circle doesnt bounce off a rect


I am building a game like breakout - a simple brick-breaker game with pygame. My problem is, i tried a rect bouncing off walls and a rect in the middle (or near) the screen and this works without any problems. Now I tried the same with a circle as a ball because it looks better and is more realistic to a brick-breaker. how can I fix, that the drawn circle bounces off the rectangle? Because on the walls, the circle bounces off.

import pygame, sys

def bouncing_rect():
    #die Variablen für die Geschwindigkeit global festlegen
    global x_speed, y_speed
    #Das "bewegende Objekt" mit der dazugehörigen Geschwindigkeit
    moving_rect.x += x_speed
    moving_rect.y += y_speed
    #Berührung mit der Wand
    if moving_rect.right >=screen_width or moving_rect.left <=0:
        x_speed *= -1
    if moving_rect.bottom >=screen_height or moving_rect.top <=0:
        y_speed *= -1
    #Hier werden die beiden Objekte, in diesem Fall Rechtecke gezeichnet
    pygame.draw.rect(screen, (255,0,255),moving_rect) #hier wird gearbietet grade!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    pygame.draw.rect(screen, (0,0,255),other_rect)
    #Berührung der Beiden Quadrate
    collision_tolerance=10
    if moving_rect.colliderect(other_rect):
        if abs(other_rect.top - moving_rect.bottom) < collision_tolerance:
            y_speed *=-1
        if abs(other_rect.bottom - moving_rect.top) < collision_tolerance:
            y_speed *=-1
        if abs(other_rect.right - moving_rect.left) < collision_tolerance:
            x_speed *=-1
        if abs(other_rect.left - moving_rect.right) < collision_tolerance:
            x_speed *=-1

def bouncing_circle():
    global xv,yv,x,y
    boooo = pygame.draw.circle(screen,'green',(x,y),40)
    var = boooo[0]  #topright
    var1 = boooo[1] #topleft
    var2 = boooo[2] #bottomleft
    var3 = boooo[3] #bottomright
    x += xv
    y += yv
    if x>1880 or x<40:
        xv *= -1
    if y>1040 or y<40:
        yv *= -1
    collision_tolerance=10
    if boooo.colliderect(other_rect):
        if abs(other_rect.top - var2) or abs(other_rect.top-var3)< collision_tolerance:
            xv *=-1
        # if abs(other_rect.top - var3 ) < collision_tolerance:
        #     yv *=-1
        if abs(other_rect.bottom - var) or abs(other_rect.bottom - var1)< collision_tolerance:
            xv *=-1
        # if abs(other_rect.bottom - var1) < collision_tolerance:
        #     yv *=-1
        if abs(other_rect.right - var1) or abs(other_rect.right - var2)< collision_tolerance:
            yv *=-1
        # if abs(other_rect.right - var2) < collision_tolerance:
        #     xv *=-1
        if abs(other_rect.left - var) or abs(other_rect.left - var3) < collision_tolerance:
            yv *=-1
        # if abs(other_rect.left - var3) < collision_tolerance:
        #     xv *=-1

#Fenster erstellen
screen_width,screen_height=1920,1080
screen = pygame.display.set_mode((screen_width,screen_height))


#Allgemeine Einstellungen
pygame.init()
pygame.display.set_caption("Marcels bahnbrechender Brick-Breaker")
clock = pygame.time.Clock()

x,y=200,200 #Kreiskoordinaten
xv,yv=5,4 #Kreis Geschwindigkeit in x-Richtung
other_rect_x,other_rect_y=850,500 #Koordinaten vom 4eck dass ich steuere

moving_rect = pygame.Rect(250,250,100,100) #Bewegendes quadrat zukünftig ball
x_speed, y_speed = 5,4                      #dessen speed
other_rect = pygame.Rect(other_rect_x,other_rect_y,200,100) #statisches rechteck

pygame.mouse.set_visible(True)
balken=pygame.mouse.set_pos(960, 540)


while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type==pygame.KEYDOWN:
            if event.key==pygame.K_RIGHT:
                other_rect_x += 20
    pygame.display.update()
    balken=pygame.mouse.get_pos()
    print(balken)
    screen.fill((224,255,255))
    pygame.draw.rect(screen, (255,0,255),moving_rect)
    pygame.draw.rect(screen, (0,0,255),(other_rect))
    bouncing_rect()
    bouncing_circle()
    pygame.display.flip()
    clock.tick(60)
    


Solution

  • The statement if abs(other_rect.top - var2) or abs(other_rect.top-var3)< collision_tolerance: checks if bool value of abs(other_rect.top - var2) is true or the second condition is fulfilled, not if either abs value is smaller than collision_tolerance. Try doing if abs(other_rect.top - var2)<collision_tolerance or abs(other_rect.top-var3)< collision_tolerance:

    the second problem is the "less than" symbol <. It triggers only after the circle is closer to an object than it should. I would suggest to change it to <=.

    The third problem is the ambigous checking of the trigger conditions. I would change

        var = boooo[0]  #topright
        var1 = boooo[1] #topleft
        var2 = boooo[2] #bottomleft
        var3 = boooo[3] #bottomright
    

    to

        var1 = boooo[1] #topleft
        var2 = boooo[2] #bottomleft
        var3 = boooo[3] #bottomright
    

    and change the if statements accordingly.