CArlos R
CArlos R

Reputation: 43

Pygame object instance speed increases

I have made this pseudo game where a ball is pursued by another, when I change the number of red balls (follower balls) the speed of the game increases, I suppose it's due to the iteration of the loop that make the moves and find collisions within the main loop, the more balls in game, the more iterations hence the increasing speed of the balls. Any suggestions in how to solve this problem?

import pygame, math, random
pygame.init()
vel = 2
ancho = 600
alto = 500
tamaño=15
tamaño_estat = tamaño *  3
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()
pos_flechas = ancho / 2, alto / 2 

posiciones_xy = []
indice = 0
lista_bolas = []
x, y = 0, 0
step = vel + 3

class Bolas():
     
    def __init__(self, color, xyb, tamaño, indice):
        super().__init__()
        self.color = color
        self.xyb = xyb
        self.tamaño = tamaño
        self.vel = vel
        self.indice = indice
        posiciones_xy.insert(self.indice,xyb)

        
    def draw(self):
        posicion = posiciones_xy[self.indice][0], posiciones_xy[self.indice][1]
        pygame.draw.circle(pantalla, self.color, posicion, self.tamaño)

    def mover(self, xyb, xyb_new, indice): # makes red balls moves towards blue ball, main ball.
        dx, dy = xyb_new[0]- xyb[0], xyb_new[1]- xyb[1]
        dist = abs(math.hypot(dx,dy))
        
        if dist > 0:
            dx, dy = round(dx * vel / dist), round(dy * vel / dist)
            xyb = [xyb[0] + dx   ,  xyb[1] + dy]
            
            if dist < vel:
               xyb = xyb_new
            posiciones_xy[indice] = xyb
        
        return xyb


    def colision(self, xyb, xyb1, indice, tamaño): # detects collision between balls
        dx, dy = round(xyb1[0]- xyb[0]), round(xyb1[1]- xyb[1])
        dist_col = abs(math.hypot(dx,dy))
        
        if dist_col < tamaño * 2 and dist_col != 0:
            colision = True
        else:
            colision = False
        
        return colision , dist_col
    
    def reaccion(self, xyb, xyb1, indice): # moves colliding balls away 
        
        if colision == True:
            dx, dy = round(xyb1[0]- xyb[0]), round(xyb1[1]- xyb[1])
            overlap = (tamaño * 2 - dist_col)/dist_col
            xyb = [xyb[0] - dx * overlap , xyb[1] - dy * overlap]
        
            if dist_col <= tamaño * 2:
                vel = 0
            posiciones_xy[indice] = xyb

    def colision_estatica(self, xyb, xyb_estatica, indice): #check and react when a ball hit central circle
        dx, dy = xyb_estatica[0] - xyb[0], xyb_estatica[1] - xyb[1]
        dist_estat = math.hypot(dx, dy)
        
        if dist_estat != 0:
            overlap = (tamaño + tamaño_estat - dist_estat) / dist_estat
        
            if dist_estat < tamaño + tamaño_estat:
                xyb = [xyb[0] - dx * overlap, xyb[1] - dy * overlap]
                posiciones_xy[indice] = xyb

    def seguir_flechas(self, xyb, xy_flechas, indice): # set main ball move with keyboard arrows
        xyb[0] += xy_flechas[0]
        xyb[1] += xy_flechas[1]
        
        if xyb[0] < 0 + tamaño:
            xyb[0] = tamaño
        
        if xyb[1] < 0 + tamaño:
            xyb[1] = tamaño
        
        if xyb[0] > ancho - tamaño:
            xyb[0] = ancho - tamaño
        
        if xyb[1] > alto - tamaño:
            xyb[1] = alto - tamaño

        posiciones_xy[indice] = xyb

def pos_ini(): # set the position where the red balls spawn
    randomX1 , randomX2 = ancho + random.randrange(10,50),  0 - random.randrange(10,50)
    x_ini = random.choice([randomX1 , randomX2])
    randomY1 , randomY2 = alto + random.randrange(10,50),  0 - random.randrange(10,50)
    y_ini = random.choice([randomY1 , randomY2])
    xyb_ini = [x_ini, y_ini]
    
    return xyb_ini

bola_ppal = Bolas(color2, [ancho / 3, alto / 3], tamaño, 0) #creates the main ball, blue, which you can control with keyboard.
lista_bolas.append(bola_ppal)

bola_central = Bolas((0,250,0), [ancho / 2, alto / 2], tamaño_estat, 1) #creates central static circle 
lista_bolas.append(bola_central)

for indice in range(2,4): # loop creates red balls, range starts  at 2 because the tow first places in the list correspond to main ball and center circle
   lista_bolas.append(Bolas(color,pos_ini(), tamaño, indice))

#main loop
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.KEYDOWN:   
            
            if event.key == pygame.K_LEFT:
                x = -step

            if event.key == pygame.K_UP:
                y = -step

            if event.key == pygame.K_RIGHT:
                x = step

            if event.key == pygame.K_DOWN:
                y = step

        if event.type == pygame.KEYUP:  

            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT: 
                x = 0

            if event.key == pygame.K_UP or event.key == pygame.K_DOWN: 
                y = 0

    pantalla.fill(negro) 
    bola_ppal.seguir_flechas(posiciones_xy[0], [x, y],0)
    pos_flechas = posiciones_xy[0]

    for indice in range(2,len(lista_bolas)):
        for indicej in range(2,len(lista_bolas)):
            
            if indice != indicej:
                
                lista_bolas[indice].mover(posiciones_xy[indice], pos_flechas,indice) 
                colision, dist_col =  lista_bolas[indice].colision(posiciones_xy[indice], posiciones_xy[indicej], indice, tamaño) 
                lista_bolas[indice].reaccion(posiciones_xy[indice], posiciones_xy[indicej], indice)
                               
               
                lista_bolas[indice].colision_estatica(posiciones_xy[indice], [ancho / 2, alto / 2]  , indice) # colision estatica bola central vs bolas perseguidor
                
                lista_bolas[indice].colision_estatica(posiciones_xy[0], [ancho / 2, alto / 2]  , 0) # colision estatica bola central con bola azul
                
                colision, dist_col =  lista_bolas[0].colision(posiciones_xy[0], posiciones_xy[indicej], 0, tamaño)  # colision con la bola principal
                lista_bolas[0].reaccion(posiciones_xy[0], posiciones_xy[indicej], 0) # reaccion bola principal
    
        lista_bolas[indice].draw()
        bola_ppal.draw()
    
        bola_central.draw()

    pygame.display.update()

pygame.quit()
quit()

Upvotes: 1

Views: 78

Answers (1)

Rabbid76
Rabbid76

Reputation: 210968

One obvious issue is that the inner loop runs from 2 to len(lista_bolas). Since you only want to move each ball once and only want to check the collisions between the balls once, it is sufficient to run the inner loop from indice+1 to len(lista_bolas).
Furthermore you need to move each ball once in the outer loop instead of repeatedly in the inner loop:

while not terminar:
    # [...]

    for indice in range(2,len(lista_bolas)):
        lista_bolas[indice].mover(posiciones_xy[indice], pos_flechas,indice) 

        for indicej in range(indice+1,len(lista_bolas)):
            
            colision, dist_col =  lista_bolas[indice].colision(posiciones_xy[indice], posiciones_xy[indicej], indice, tamaño) 
            lista_bolas[indice].reaccion(posiciones_xy[indice], posiciones_xy[indicej], indice)
                               
            lista_bolas[indice].colision_estatica(posiciones_xy[indice], [ancho / 2, alto / 2]  , indice) # colision estatica bola central vs bolas perseguidor
            lista_bolas[indice].colision_estatica(posiciones_xy[0], [ancho / 2, alto / 2]  , 0) # colision estatica bola central con bola azul
            
            colision, dist_col =  lista_bolas[0].colision(posiciones_xy[0], posiciones_xy[indice], 0, tamaño)  # colision con la bola principal
            lista_bolas[0].reaccion(posiciones_xy[0], posiciones_xy[indice], 0) # reaccion bola principal
    
        lista_bolas[indice].draw()
    
    bola_ppal.draw()
    bola_central.draw()
    pygame.display.update()

Upvotes: 1

Related Questions