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.
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.