I am trying to rewrite some code to take advantage of pygame sprites in Boids Algorithm implementation. Currently the goal is to create multiple sprites on screen (number determined by "flock" variable) and get them moving in random directions, avoiding the edges.
I have succeeded in doing so with a single sprite, as well as just using non-pygame circles. But now, instead of multiple moving rectangles, I seem to only get one.
I tried calling the redraw function and/or updating the surface in various different loops, assuming that the issue was in the order of execution. The results vary from only one well behaving sprite to none at all to a random tantrum of squares.
I assume the problem is in the way or order I append the objects to the parent array and drawing them.
def redraw():
for boids in birds:
boids.draw(win)
pygame.display.update()
#Creating a parent array with all boids objects
birds = pygame.sprite.Group()
for i in range (flock):
#Randomizing the starting position of the new boid within the margins before adding it to the array
posx = random.randint(l_margin, r_margin)
posy = random.randint(t_margin, b_margin)
#Creating the new boid and adding it to the array
boids = boid(posx, posy, turnf, avel_x, avel_y, margins)
birds.add(boids)
OR the problem may lie somewhere in the boid class that governs the sprite behaviour. Full code below.
import pygame
import random
pygame.init()
pygame.mixer.init()
#Screen size
d_width = 400
d_height = 400
margins = 50
#Determinig the boundaries of the play area
l_margin = d_width - (d_width - margins)
r_margin = d_width - margins
t_margin = d_height - (d_height - margins)
b_margin = d_height - margins
win = pygame.display.set_mode((d_width, d_height))
pygame.display.set_caption("Boids Algorithm")
win.fill((0,0,0))
#Asigning a random integer between -6 and 6 for boid velocity
avel_x = random.randint(-6, 6)
avel_y = random.randint(-6, 6)
#Asigning values to the turn factor of the boid and number of boids in a flock
turnf = 2
flock = 10
FPS = 10
clock = pygame.time.Clock()
#Class containing all properties of boids
class boid(pygame.sprite.Sprite):
def __init__(self, x, y, turnfactor, vel_x, vel_y, margin):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10,10))
self.image.fill((255,255,255))
self.rect = pygame.Rect(x, y, 5,5)
self.rect.x = x
self.rect.y = y
#self.rect.radius = radius
self.turnfactor = turnfactor
self.velx = vel_x
self.vely = vel_y
self.margin = margin
def move (self):
#Updating position for every frame
self.rect.x = self.rect.x + self.velx
self.rect.y = self.rect.y + self.vely
#Checking if the new position of the boid is past the margin. If true, aply a turn factor to velocity to start turning the boid
if self.rect.x < l_margin:
self.velx = self.velx + self.turnfactor
elif self.rect.x > r_margin:
self.velx = self.velx - self.turnfactor
elif self.rect.y < t_margin:
self.vely = self.vely + self.turnfactor
elif self.rect.y > b_margin:
self.vely = self.vely - self.turnfactor
#A list with updated position
self.position = (self.rect.x, self.rect.y)
def draw(self, win):
#Filling the screen with black, obtaining new position for the boid from move() and redrawing at the new position
win.fill((0,0,0))
self.move()
win.blit(self.image, self.position)
#pygame.display.update()
def redraw():
for boids in birds:
boids.draw(win)
pygame.display.update()
#Creating a parent array with all boids objects
birds = pygame.sprite.Group()
for i in range (flock):
#Randomizing the starting position of the new boid within the margins before adding it to the array
posx = random.randint(l_margin, r_margin)
posy = random.randint(t_margin, b_margin)
#Creating the new boid and adding it to the array
boids = boid(posx, posy, turnf, avel_x, avel_y, margins)
birds.add(boids)
run = True
fly = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw()
pygame.quit()
You must delete the display only once, but not for each body. pygame.Surface.fill
fills the entire display with a uniform color and hides everything on that surface that was drawn prior to this function.
class boid(pygame.sprite.Sprite):
# [...]
def draw(self, win):
#Filling the screen with black, obtaining new position for the boid from move() and redrawing at the new position
# win.fill((0,0,0)) <--- DELETE
self.move()
win.blit(self.image, self.position)
def redraw():
win.fill((0,0,0)) # <--- INSERT
for boids in birds:
boids.draw(win)
pygame.display.update()