Reputation: 43
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
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