Create Particle Effect Animation Using Python

If you’ve been dabbling in Python and are looking to get started with animation effects or want to add some visual flair to your projects, you’ve come to the right place.

Today, we’re going to chat about creating a supercool particle effect animation, akin to a fountain of particles that dance up into the air before gracefully descending back down.

Some powerful Python libraries like OpenCV, Matplotlib, and Numpy can be used for animation effects, but Pygame adds another dimension to your animation game.

Usually, Pygame is used for the development of games using Python, but Pygame can also be used for creating video effects thanks to its animation capabilities.

Pygame particle effects

Imagine a point on a blank canvas. This isn’t just any point; it’s about to become the source of an animated fountain of particles.

These little dots will burst forth, rise a bit, and then obey the laws of gravity as they fall, much like water in a fountain or fireworks against the night sky.

pygame particle effects

We’re going to walk through the process of creating this simple particle effect animation using Python and Pygame, and how to save it as a video file.

Setting Up the Environment

First, make sure to have Python installed on your system along with the Pygame and Moviepy libraries. Pygame will be used for creating the animation, while Moviepy will allow us to save our animation as a video.

Or you can use Google Colab like me which has both Pygame and Moviepy pre-installed.

import pygame
import random
from moviepy.editor import ImageSequenceClip
import numpy as np

Define constant parameters for the animation video

# Constants
WIDTH, HEIGHT = 800, 600 # Dimensions of frame
BACKGROUND_COLOR = (0, 0, 0)
PARTICLE_COLOR = (252, 177, 3)
GRAVITY = np.array([0, 0.2])
DURATION = 10  # Duration of the animation in seconds
FPS = 40  # Frames per second (FPS)

Create Particle class

The core of our particle effect is the Particle class.

Each particle will have a position and velocity. Upon initialization, a particle’s position is set, and a random velocity is given to it, so it appears to shoot upwards.

The update() method modifies the velocity by adding a constant gravity force which will simulate the natural path of a particle through the air, eventually causing it to fall.

class Particle:
    def __init__(self, position):
        self.position = np.array(position, dtype=float)
        self.velocity = np.array([random.uniform(-2, 2), random.uniform(-5, -2)], dtype=float)
        self.alive = True

    def update(self):
        if self.position[1] < HEIGHT and self.alive:
            self.velocity += GRAVITY
            self.position += self.velocity
        else:
            self.alive = False

    def draw(self, surface):
        if self.alive:
            pygame.draw.circle(surface, PARTICLE_COLOR, self.position.astype(int), 3)

Generate particle animation frames

In the main loop, we’re doing several things:

  • Updating the screen with a black background.
  • Generating new particles and adding them to the list.
  • Updating and drawing each particle.
  • Removing particles that are no longer “alive” or visible on the screen.
  • Capturing each frame as an array to be used later for creating the video.
# Initialize Pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Fountain Sparkles Animation")
clock = pygame.time.Clock()

# Record the frame data
frames = []
particles = []

# The main loop
running = True
start_ticks = pygame.time.get_ticks()
while running:
    seconds = (pygame.time.get_ticks() - start_ticks) / 1000  # Calculate how many seconds
    if seconds > DURATION:  # Duration of the video
        running = False

    # Fill the background color
    screen.fill(BACKGROUND_COLOR)

    # Emit new particles
    if len(particles) < 200:  # Limit the number of particles
        particles.append(Particle((WIDTH // 2, HEIGHT // 2)))

    # Update particles
    for particle in particles:
        particle.update()

    # Remove dead particles
    particles = [particle for particle in particles if particle.alive]

    # Draw particles
    for particle in particles:
        particle.draw(screen)

    # Update the display
    pygame.display.flip()

    # Save the current frame
    frame_data = pygame.surfarray.array3d(screen)
    frames.append(frame_data)

    # Limit frames per second
    clock.tick(FPS)

# Quit Pygame
pygame.quit()

Once the desired duration of the animation is reached, we exit the main loop, quit Pygame, and use Moviepy to convert our series of frames into a continuous video.

Save Pygame animation as MP4 video

The ImageSequenceClip function creates a video clip from the frames we recorded. We then save the video clip as “fountain_animation.mp4”.

# Create a moviepy video clip
clip = ImageSequenceClip([frame.swapaxes(0, 1) for frame in frames], fps=FPS)

# Write the video file
clip.write_videofile("fountain_animation.mp4")

Particle effect animation with moving source

Let’s make the particle animation a bit more interesting. We can easily make the source or the particle emitter move horizontally.

Most of the code will remain the same except the main loop as shown below.

# Initialize Pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Moving Fountain Sparkles Animation")
clock = pygame.time.Clock()

# Record the frame data
frames = []
particles = []

# Emitter settings
emitter_position = np.array([WIDTH // 4, HEIGHT // 2], dtype=float)  # Starting position
emitter_velocity = np.array([2, 0], dtype=float)  # Horizontal velocity
emitter_end_position = WIDTH * 3 // 4  # End position

# The main loop
running = True
start_ticks = pygame.time.get_ticks()
while running:
    seconds = (pygame.time.get_ticks() - start_ticks) / 1000  # Calculate how many seconds
    if seconds > DURATION:  # Duration of the video
        running = False

    # Update emitter position
    emitter_position += emitter_velocity
    # Stop emitter at the end position
    if emitter_velocity[0] > 0 and emitter_position[0] >= emitter_end_position or \
       emitter_velocity[0] < 0 and emitter_position[0] <= WIDTH // 4:
        emitter_velocity[0] = 0

    # Fill the background color
    screen.fill(BACKGROUND_COLOR)

    # Emit new particles
    if len(particles) < 200:  # Limit the number of particles
        particles.append(Particle(emitter_position.copy()))

    # Update particles
    for particle in particles:
        particle.update()

    # Remove dead particles
    particles = [particle for particle in particles if particle.alive]

    # Draw particles
    for particle in particles:
        particle.draw(screen)

    # Update the display
    pygame.display.flip()

    # Save the current frame
    frame_data = pygame.surfarray.array3d(screen)
    frames.append(frame_data)

    # Limit frames per second
    clock.tick(FPS)

# Quit Pygame
pygame.quit()

After generating the frames, you can again save them as a new video.

# Create a moviepy video clip
clip = ImageSequenceClip([frame.swapaxes(0, 1) for frame in frames], fps=FPS)

# Write the video file
clip.write_videofile("moving_fountain_animation.mp4")

Conclusion

Through this example, we’ve seen how straightforward it can be to create a particle effect animation with Pygame. Whether for game development, simulations, or just for fun, particle systems are a fascinating and visually engaging way to approach creative coding in Python.

Remember, this is just the tip of the iceberg. Pygame allows for far more complex and interactive graphics programming. So take this as a starting point for your journey into the world of visual effects and game development with Python.

Leave a Reply

Your email address will not be published. Required fields are marked *