0

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)
    

Dimyyy
  • 5
  • 2
  • @Rabbid76 Author has already made bouncing from walls (not good though), he needs bouncing from rectangular object inside the frame, so it is not duplicate. – MBo Sep 30 '22 at 18:30
  • @MBo [How do I avoid an glitchy collision between circle and rectangle in PyGame?](https://stackoverflow.com/questions/58139771/how-do-i-avoid-an-glitchy-collision-between-circle-and-rectangle-in-pygame/58145450#58145450) (In fact nearly every pygame question is duplicate) – Rabbid76 Sep 30 '22 at 18:32
  • @Rabbid76 OK, this one is correct reason :) – MBo Sep 30 '22 at 18:33

2 Answers2

0

For circle with center coordinates (cx, cy) you can calculate squared distance from circle center to rectangle (picture here)

dx = Max(Abs(cx - rect.center.x) - rect.width / 2, 0)
dy = Max(Abs(cy - rect.center.y) - rect.height / 2, 0)
SquaredDistance = dx * dx + dy * dy

and compare it with squared radius.

You can classify collision edge or corner with signs of dx and dy (both nonzero - corner etc).

If you want to precalculate the moment of collision, look here

P.S. I see that pygame.rect has collidecircle method (cannot see docs page though), so it's worth to use ready methods

MBo
  • 77,366
  • 5
  • 53
  • 86
0

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.

wikwoj
  • 203
  • 2
  • 6