0

I'm trying to make one ball push another, the problem is that when the balls collide the red ball gets into the blue, the red moves towards the left mouse click, the blue one is drawn with the right mouse click. I've noticed that the speed (Velocidad) and

        self.xb2-=self.dx+overlapx/(tamaño/2)
        self.yb2-=self.dy+overlapy/(tamaño/2)

the magnitude of the divisor, tamaño/2, has a significant role in the problem.

here's the code

import pygame, math, random
pygame.init()
vel = 5
ancho = 600
alto = 500
tamaño=30
color = (250,0,0)
color2= (0,0,250)
FPS=60
negro= 0,0,0
posantes = [[300,250], [- 50, - 50]]   #posicion anterior, bola  y bola1/ initial position bola , initial position bola1
mouse = [[300,250], [ - 50, - 50]]            #posicion mouse, click izquierdo  , click derecho
pantalla = pygame.display.set_mode((ancho, alto))
reloj = pygame.time.Clock()
class Bola():
    def __init__(self, color, xyb, tamaño):
        super().__init__()
        pygame.draw.circle(pantalla, color, xyb,tamaño)
        
    def colision(self,xyb,xyb2):
        self.colision = False
        self.xyb = posantes [0]
        self.xyb2 = posantes[1]
        self.xb,self.yb = posantes[0][0],posantes[0][1]
        self.xb2,self.yb2 = posantes[1][0],posantes[1][1]
        dist = math.hypot(self.xb2-self.xb,self.yb2-self.yb)
       
        if dist<tamaño*2:
            self.colision =True
        else:
            self.colision =False
        
    def reaccion(self,xyb,xyb2):
        overlapx , overlapy = self.xb-self.xb2, self.yb-self.yb2    
        if self.colision==True:
          
            self.xb2-=self.dx+overlapx/(tamaño/2)
            self.yb2-=self.dy+overlapy/(tamaño/2)
            posantes[1]=[self.xb2,self.yb2]
            print(" !! reaccion   ¡¡")
    
    def moverbola(self, xyb, xy,bi):
        
        self.xyb = posantes[bi]
        self.xy  = mouse[bi]
        self.xb,self.yb = self.xyb[0] , self.xyb[1]
        self.x,self.y = self.xy[0] , self.xy[1]
        self.dx,self.dy = abs(self.x-self.xb) , abs(self.y-self.yb)
        dist = math.hypot(self.x-self.xb,self.y-self.yb)
       
        if   dist!= 0:
            self.dx = self.dx / dist
            self.dy = self.dy / dist
    
        if self.xb < self.x:
            self.xb+=vel * self.dx
        if self.xb > self.x:
            self.xb-=vel * self.dx
        if self.yb < self.y:
            self.yb+=vel * self.dy
        if self.yb > self.y :
            self.yb -=vel * self.dy
        self.xyb = [self.xb,self.yb]
        posantes[bi] = self.xyb
      
    
terminar = False
    
while not terminar:
    reloj.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            terminar=True
        if event.type == pygame.MOUSEBUTTONDOWN and event.button==1:
            mouse[0] = pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1]
        if event.type == pygame.MOUSEBUTTONDOWN and event.button==3:
            mouse[1] = pygame.mouse.get_pos()[0],pygame.mouse.get_pos()[1] 
            posantes[1] = mouse[1]
           
    pantalla.fill(negro)
    bola1 = Bola(color2, posantes[1], tamaño)
    bola = Bola(color,posantes[0], tamaño)
    bola.moverbola(posantes[0], mouse[0],0)
    bola.colision(posantes[0],posantes[1])
    bola.reaccion(posantes[0],posantes[1])
   
   
    
    pygame.display.update()
     
pygame.quit()
quit()
cokeman19
  • 2,405
  • 1
  • 25
  • 40
CArlos R
  • 43
  • 5
  • See [Pygame how to let balls collide](https://stackoverflow.com/questions/63145493/pygame-how-to-let-balls-collide/63187016#63187016) and [pygame Get the balls to bounce off each other](https://stackoverflow.com/questions/63586822/pygame-get-the-balls-to-bounce-off-each-other/63587147#63587147) – Rabbid76 Mar 20 '21 at 12:16

1 Answers1

0

You misunderstood the concept of object-oriented programming. You must create instances of the Bola class before the application loop, but use them in the loop:

bola1 = Bola(color2, [-50, -50], tamaño)
bola = Bola(color, [300, 250], tamaño)

terminar = False
while not terminar:

    bola1.draw()
    bola.draw()

Set the attribute Bola in the constructor and use it in the methods, e.g. B. to draw the Bola:

class Bola():
    def __init__(self, color, xyb, tamaño):
        super().__init__()
        self.color = color
        self.xyb = xyb
        self.tamaño = tamaño

    def draw(self):
        pos = round(self.xyb[0]), round(self.xyb[1])
        pygame.draw.circle(pantalla, self.color, pos, self.tamaño)

Ensure methods and attributes have different names (collision, colision_test). The colision_test method returns the result of the test:

class Bola():
    # [...]

    def colision_test(self,xyb2):
        dist = math.hypot(xyb2[0] - self.xyb[0], xyb2[1] - self.xyb[1])
        self.colision = dist < tamaño*2
        return (self.colision, dist)

Move the Bola in the reaccion and moverbola methods depending on the arguments of the function and change the attribute in which the position is stored:

class Bola():
    # [...]

    def reaccion(self, xyb_other, reaction_dist):
        dx, dy = xyb_other[0] - self.xyb[0], xyb_other[1] - self.xyb[1]
        dist = math.hypot(dx, dy)
        if dist > 0:
            self.xyb = [self.xyb[0] - dx * reaction_dist / dist, self.xyb[1] - dy * reaction_dist / dist]

    def moverbola(self, target):
        dx, dy = target[0] - self.xyb[0], target[1] - self.xyb[1]
        dist = math.hypot(dx, dy)
        if dist > 0:
            step = min(dist, vel)
            self.xyb = [self.xyb[0] + dx * step / dist, self.xyb[1] + dy * step / dist]

Complete exmaple:

import pygame, math, random
pygame.init()
vel = 5
ancho = 600
alto = 500
tamaño=30
color = (250,0,0)
color2= (0,0,250)
FPS=60
negro= 0,0,0

pantalla = pygame.display.set_mode((ancho, alto))
reloj = pygame.time.Clock()

class Bola():
    def __init__(self, color, xyb, tamaño):
        super().__init__()
        self.color = color
        self.xyb = xyb
        self.tamaño = tamaño

    def draw(self):
        pos = round(self.xyb[0]), round(self.xyb[1])
        pygame.draw.circle(pantalla, self.color, pos, self.tamaño)
        
    def colision_test(self,xyb2):
        dist = math.hypot(xyb2[0] - self.xyb[0], xyb2[1] - self.xyb[1])
        self.colision = dist < tamaño*2
        return (self.colision, dist)
        
    def reaccion(self, xyb_other, reaction_dist):
        dx, dy = xyb_other[0] - self.xyb[0], xyb_other[1] - self.xyb[1]
        dist = math.hypot(dx, dy)
        if dist > 0:
            self.xyb = [self.xyb[0] - dx * reaction_dist / dist, self.xyb[1] - dy * reaction_dist / dist]

    def moverbola(self, target):
        dx, dy = target[0] - self.xyb[0], target[1] - self.xyb[1]
        dist = math.hypot(dx, dy)
        if dist > 0:
            step = min(dist, vel)
            self.xyb = [self.xyb[0] + dx * step / dist, self.xyb[1] + dy * step / dist]
      
bola1 = Bola(color2, [-50, -50], tamaño)
bola = Bola(color, [300, 250], tamaño)
bola_target = [300, 250]

terminar = False
while not terminar:
    reloj.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            terminar=True
        if event.type == pygame.MOUSEBUTTONDOWN and event.button==1:
            bola_target = event.pos
        if event.type == pygame.MOUSEBUTTONDOWN and event.button==3:
            bola1.xyb = event.pos
           
    bola.moverbola(bola_target)
    collision, dist = bola1.colision_test(bola.xyb)
    if collision:
        reaccion = (tamaño * 2 - dist)
        bp = bola.xyb[:]
        bp1 = bola1.xyb[:]
        bola.reaccion(bp1, reaccion)
        bola1.reaccion(bp, reaccion)
   
    pantalla.fill(negro)
    bola1.draw()
    bola.draw()
    pygame.display.update()
     
pygame.quit()
quit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Could you explain why the reaction is equal to self.xyb = [self.xyb[0] - dx * reaction_dist / dist, self.xyb[1] - dy * reaction_dist / dist] I understand that dx and dy divided by dist normalize the vector, are you doing the same with reaction_dist / dist? I dont understand also, this line step = min(dist, vel) Thx – CArlos R Mar 20 '21 at 23:12
  • `(dx / dist, dy /dist)` is the normalized distance and `(dx * reaction_dist / dist, dy * reaction_dist / dist)` is a vector with the length `reaction_dist `. `Bola` should not step over the target. If the distance to the target is less then `vel`, the step has to be limited. Hence `step = min(dist, vel)` – Rabbid76 Mar 20 '21 at 23:17