Create trails of particles for the bullets

Viewed 97

I'm creating a space shooting game in which a spaceship will fire out bullets every time the user clicks the left mouse and since I want the bullets to be a bit fancier I want them to have a trail of particles behind them after being fired. I tried something to my code (which ended up to be the code that I'll show below) yet the result isn't good.

  1. The particles keep sticking to the bullets.
  2. Only one particle appeared.

What should I do to fix this? This is my code:

bullet_surf = pygame.image.load('graphics for b/beam.png')
bullet_surf = pygame.transform.rotozoom(bullet_surf,0,0.08)
bullets = []
while True:
....    
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                bullets.append([[*ship_rect.midright],6,[random.randint(-20,20)/10,random.randint(-20,20)/10]])
    
    for b in range(len(bullets)):
        bullets [b][0][0] +=20
    
    for bullet in bullets[:]:
        if bullet [0][0] > 1100:
            bullets.remove(bullet)
    
    for bullet in bullets:
        bullet_rect = bullet_surf.get_rect(midleft = (bullet[0][0],bullet[0][1]))
        screen.blit(bullet_surf,bullet_rect)
        bullet_rect.centerx += bullet[2][0]
        bullet_rect.centery += bullet[2][1]
        bullet[1] -= 0.1
        print(bullet_rect.center)
        pygame.draw.circle(screen,(255,255,255),bullet_rect.center,int(bullet[1])) 
1 Answers

You need to create a list of particles for each bullet. I suggest using a Class for the bullets:

self.particles = []

Add a new particle to the list and animate the particles in the list as the bullet moves:

for particle in self.particles:
    particle[0][0] -= 2
    particle[0][1] += particle[1]
particle = [list(self.rect.midleft), random.uniform(-2, 2), pygame.Color(255, random.randrange(255), 0)]
self.particles.append(particle)
if len(self.particles) > 30:
    self.particles.pop(0)

Draw all the particles in the list in a loop:

for i, particle in enumerate(self.particles):
    pygame.draw.circle(screen, particle[2], particle[0], (i//3+2))

Minimal example

import pygame, random

pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()

class Bullet:
    def __init__(self, x, y):
        self.image = pygame.image.load("rocket.png")
        self.rect = self.image.get_rect(center = (x, y))
        self.particles = []

    def move(self):
        for particle in self.particles:
            particle[0][0] -= 2
            particle[0][1] += particle[1]
        particle = [list(self.rect.midleft), random.uniform(-2, 2), pygame.Color(255, random.randrange(255), 0)]
        self.particles.append(particle)
        if len(self.particles) > 30:
            self.particles.pop(0)
        self.rect.centerx += 3

    def draw(self, screen):
        for i, particle in enumerate(self.particles):
            pygame.draw.circle(screen, particle[2], particle[0], (i//3+2))
        screen.blit(self.image, self.rect)
        

background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *background.get_size(), (32, 32, 32), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles] 

bullet = Bullet(0, 100)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 
        
    bullet.move()
    if bullet.rect.left >= 400:
        bullet.rect.right = 0

    window.blit(background, (0, 0))
    bullet.draw(window)
    pygame.display.flip()
    clock.tick(100)

pygame.quit()
exit()

Example of firing bullets by mouse click:

import pygame, random

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

class Bullet:
    def __init__(self, x, y):
        self.image = pygame.image.load("rocket.png")
        self.rect = self.image.get_rect(center = (x, y))
        self.particles = []

    def move(self):
        for particle in self.particles:
            particle[0][0] -= 2
            particle[0][1] += particle[1]
        particle = [list(self.rect.midleft), random.uniform(-2, 2), pygame.Color(255, random.randrange(255), 0)]
        self.particles.append(particle)
        if len(self.particles) > 30:
            self.particles.pop(0)
        self.rect.centerx += 3

    def draw(self, screen):
        for i, particle in enumerate(self.particles):
            pygame.draw.circle(screen, particle[2], particle[0], (i//3+2))
        screen.blit(self.image, self.rect)
        

background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *background.get_size(), (32, 32, 32), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles] 

bullets = []    

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 
        if event.type == pygame.MOUSEBUTTONDOWN:
            bullets.append(Bullet(*event.pos))

    for bullet in bullets[:]:     
        bullet.move()
        if bullet.rect.left >= 400:
            bullets.remove(bullet)

    window.blit(background, (0, 0))
    for bullet in bullets[:]:    
        bullet.draw(window)
    pygame.display.flip()
    clock.tick(100)

pygame.quit()
exit()
Related