Particles effects in videogames with Pygame and Python

Particles are fun and creates very attracting visual effects in games, so we will see how to make them.

Particles

Show them all – code

import pygame
import random

pygame.init()
window = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Press right arrow key to start")
window2 = pygame.Surface((600, 400))
clock = pygame.time.Clock()

group = []
class Particles(pygame.sprite.Sprite):
    "Creates particles starting from pos with a color"

    def __init__(self, pos, y_dir, color, sparse=0, turn="off"):
        super(Particles, self).__init__()
        self.particles_list = []
        self.pos = pos
        self.color = color
        self.y_dir = y_dir
        self.sparse = sparse # generate particles not from the same starting point
        # self.generate_particles()
        group.append(self)
        self.turn = turn # this makes the effect visible

    def choose_y_dir(self):
        "Makes particles go in every direction you want"

        # Make the flow go down
        if self.y_dir == "down":
            y_dir = 2

        elif self.y_dir == "up":
            y_dir = -2

        # Make the particles spread all y_dirs
        elif self.y_dir == "all":
            y_dir = random.randrange(-2, 2, 1)

        return y_dir

    def generate_particles(self):
        "List with position etc of particles"

        if self.sparse == 1:
            self.pos[0] = random.randint(0, 600)

        # setting the data for each particles
        origin = [self.pos[0], self.pos[1]] # Starting here each particles
        y_dir = self.choose_y_dir()
        x_dir = random.randint(0, 20) / 10 - 1
        dirs = [x_dir, y_dir] # movement
        radius = random.randint(4,6) # radius
        # Appending data to the list
        self.particles_list.append([origin, dirs, radius])
        self.generate_movements()

    def generate_movements(self):
        
        # Moving the coordinates and size of self.particles_list
        for particle in self.particles_list[:]:
            particle[0][0] += particle[1][0] # x pos += x_dir
            particle[0][1] += particle[1][1] # y pos += y_dir
            particle[2] -= 0.05 # how fast circles shrinks
            particle[1][1] += 0.01 # circles speed
            # if particle[2] <= 0:
            if particle[2] <= 0:
                self.particles_list.remove(particle)
            # do not call draw from here: it slows down the frame rate
            # self.draw()
    
    def draw(self):
        "Draws particles based on data in the self.particles_list"
        if self.turn == "on":
            for particle in self.particles_list:
                 pygame.draw.circle(
                    window2, (self.color),
                (round(particle[0][0]), round(particle[0][1])),
                 round(particle[2]))

p1 = 1
# Some random colors
RED = (255, 0, 0) 
GREEN = (0, 255, 0)
YELLOW = (255, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
# Creating the list with particles ready to be drawn

Particles([100, 200], y_dir="up", color=RED)
Particles([100, 200], y_dir="down", color=GREEN)
Particles([200, 100], y_dir="down", color=YELLOW)
Particles([300, 100], y_dir="all", color=BLUE)
Particles([400, 100], y_dir="down", color=CYAN)
Particles([500, 200], y_dir="up", color=GREEN)
Particles([0, 0], y_dir="down", color=WHITE, sparse=1)
Particles([0, 400], y_dir="up", color=YELLOW, sparse=1)
Particles([0, 200], y_dir="up", color=RED, sparse=1)
Particles([0, 200], y_dir="down", color=BLUE, sparse=1)
Particles([100, 200], y_dir="all", color=BLUE, sparse=1)



def generate():
    "Start drawing all circles on the screen"
    for par in group:
        par.generate_particles()
        par.draw()

# ================= INFINITE LOOP ================== #
n = 0 # points to an effect in the group list
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                group[n].turn = "off"
            elif event.key == pygame.K_RIGHT:
                group[n].turn = "on"
            n += 1
            if n > len(group) - 1:
                n = 0
    window2.fill(0)
    generate()
    window.blit(window2, (0, 0))
    clock.tick(60)
    pygame.display.flip()
# ================================ END OF LOOP ==== #

Other particles effect

This one is more simple. It is based on some code of daflufflypotato.

#!/usr/bin/python3.4
# Setup Python ----------------------------------------------- #
import pygame, sys, random

# Setup pygame/window ---------------------------------------- #
mainClock = pygame.time.Clock()
from pygame.locals import *
pygame.init()
pygame.display.set_caption('game base')
screen = pygame.display.set_mode((500, 500),0,32)

TILE_SIZE = 20

# [loc, velocity, timer]
particles = []

tile_map = {}
for i in range(10):
    tile_map[str(i + 4) + ';14'] = [i + 4, 14, (255, 0, 0)]

# tile_map['15;10'] = [15, 10, (0, 0, 255)]
# tile_map['15;11'] = [15, 11, (0, 0, 255)]
# tile_map['15;12'] = [15, 12, (0, 0, 255)]
# tile_map['15;13'] = [15, 13, (0, 0, 255)]

# tile_map['11;11'] = [11, 11, (0, 255, 255)]
# tile_map['11;12'] = [11, 12, (0, 255, 255)]

clicking = False


def particles_explosion(particles):
    for particle in particles:
        particle[0][0] += particle[1][0] # coordinate sull'asse x
        # stringa con riga e colonna dello schema dello schermo che nel dizionario...
        loc_str = str(int(particle[0][0] / TILE_SIZE)) + ';' + str(int(particle[0][1] / TILE_SIZE))
        # rimbalza su verticali
        # Se si trova quindi a contatto con un tile rimbalza
        if loc_str in tile_map:
            particle[1][0] = -0.7 * particle[1][0]
            particle[1][1] *= 0.95
            particle[0][0] += particle[1][0] * 2
        particle[0][1] += particle[1][1]
        loc_str = str(int(particle[0][0] / TILE_SIZE)) + ';' + str(int(particle[0][1] / TILE_SIZE))
        if loc_str in tile_map:
            # Rimbalza in orizzontale
            particle[1][1] = -0.7 * particle[1][1]
            particle[1][0] *= 0.95
            particle[0][1] += particle[1][1] * 2
        particle[2] -= 0.035
        particle[1][1] += 0.15
        # ============= ecco le particles ==================
        pygame.draw.circle(screen, (255, 255, 255), [int(particle[0][0]), int(particle[0][1])], int(particle[2]))
        if particle[2] <= 0:
            particles.remove(particle)



# Loop ------------------------------------------------------- #
while True:
    
    # Background --------------------------------------------- #
    screen.fill((0,0,0))
    mx, my = pygame.mouse.get_pos()

    # Particles ---------------------------------------------- #
    if clicking:
        for i in range(10):
            particles.append(
                [[mx, my], [random.randint(0, 42) / 6 - 3.5, random.randint(0, 42) / 6 - 3.5], random.randint(4, 6)])
    particles_explosion(particles)


    # Render Tiles ------------------------------------------- #
    for tile in tile_map:
        # ----------------surface---------- colore--------------- 
        pygame.draw.rect(screen, tile_map[tile][2], 
            # coordinate del rettangolo
            pygame.Rect(tile_map[tile][0] * TILE_SIZE, tile_map[tile][1] * TILE_SIZE, TILE_SIZE, TILE_SIZE))
    
    # Buttons ------------------------------------------------ #
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()

        if event.type == MOUSEBUTTONDOWN:
            if event.button == 1:
                # for i in range(10):
                    clicking = True
                    particles.append(
                        [
                         [mx, my], # posizione iniziale
                         [random.randint(0, 42) / 6 - 3.5, # direzione con una certa casualità
                         random.randint(0, 42) / 6 - 3.5],
                         random.randint(4, 6)]) # grandezza delle sfere

        # if event.type == MOUSEBUTTONUP:
        #     if event.button == 1:
        #         clicking = False
                
    # Update ------------------------------------------------- #
    pygame.display.update()
    mainClock.tick(60)

When you click somewhere some particles are generated and these will collide with some surfaces on the screen.


Subscribe to the newsletter for updates
Tkinter templates
Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.