Let’s dive into the code to make particles that we’ve see in the last post.
I made some changes to the code, as you can see comparing the two versions.
The list with the parameters for the snow flakes
I’ve put the list for the particles (the parameters of the particles, that are the circles that will rapresent the flakes) into this class
# pygame.math module # https://www.pygame.org/docs/ref/math.html # # Pygame swap text with another text # https://stackoverflow.com/questions/60944070/pygame-swap-text-with-another-text/60953697#60953697 # # GitHub - PyGameExamplesAndAnswers - Draw 2D - list_of_particles # https://github.com/Rabbid76/PyGameExamplesAndAnswers/blob/master/documentation/pygame/pygame_2D.md import pygame import random import sys pygame.mixer.init() jingle = pygame.mixer.music.load("snow.mp3") class Particle: def __init__(self): "Setting up screen, clock and loading images" pygame.init() self.screen = pygame.display.set_mode((800, 600)) self.frame_rate = pygame.time.Clock().tick self.snow = pygame.image.load("snow6.png").convert() self.cloud = pygame.image.load("cloud.png") self.window2 = pygame.image.load("snow5.png") self.list_of_particles = [] def update(self): "How to quit the window" self.frame_rate(60) for event in pygame.event.get(): if event.type == pygame.QUIT: self.run = False self.images_display() def images_display(self): "Make snow fall down - blitting images and calling the flake generator" self.screen.blit(self.snow, (0,0)) self.snow_flakes_generator() self.screen.blit(self.cloud, (-110,-100)) self.screen.blit(self.cloud, (-50, 250)) self.screen.blit(self.cloud, (450, 250)) self.screen.blit(self.window2, (0, 0)) pygame.display.flip() def mainloop(self): "A call to the self.update method to run stuffs" pygame.mixer.music.play() self.run = True while self.run: run = self.update() pygame.quit() exit() # the surface with the snow as a background def generate_one_particle(self): starting_pos = [random_pos(), 50] # direction of x and next y pos incremented of 0.01 move_pos = [random.randint(0, 20) / 10 - 1, 2] radius = random.randint(4, 6) return [starting_pos, move_pos, radius] def snow_flakes_generator(self): "circles move from random start position at the top until bottom and the disappear" self.list_of_particles.append(self.generate_one_particle()) # Every particle moves... if list_of_particles[2] (the radius) is >= than 0 it is removed for particle in self.list_of_particles[:]: # parameters for new position (aka speed) and shrinking direction = particle[1][0] # random direction fixed velocity = particle[1][1] # get the next position on the y axes gravity = 0.01 # how fast it falls melting = 0.005 # how fast it shrinks # the starting point changes going right or left particle[0][0] += direction # increase the x position of an angle (to the right or left) particle[0][1] += velocity # the y movement going down speed fixed 2 # but it is increased of 0.01 down here, so it goes down at the same speed particle[2] -= melting # the snowflake shriks particle[1][1] += gravity # * random.randint(-3, 6) # increase down speed a bit if particle[2] <= 0: # when the radius is 0 it is removed, so we do not see it anymore and it's not in the memory self.list_of_particles.remove(particle) # draws a circle on the screen white, at x y corrds and with a ray of particle[2] for particle in self.list_of_particles: pos = particle[0][0] speed = particle[0][1] radius = particle[2] # circle: surface, color, pos, radius pygame.draw.circle( self.screen, (255, 244, 255), # color ( round(pos), # Pos x, y round(speed)), # direction / speed round(radius)) # radius def random_pos(): " to make a flame like list_of_particles [150, 20] # flame, so that all circles with start at the same point" return random.randint(30, 8000) # return 150 fx = Particle() fx.mainloop()
In this list we will have:
- a first list with x and y intergers for the position on the screen of the snow flakes
- a second list with the angle of the direction of the snow flake and the new pos towards down
- the size of the radius (when 0 the particle parameters will be deleted)
so it will be like (for just one particle)…
list_of_particle = [[20, 0], [0.5, 2], 4]
The first two [2, 0], is the original position on top of the screen (the 20 is randomly generated)
The second two [0.5, 2] is the angle addedd each time (so it will go to left or right randomly) and the falling speed that will be increased of 0.01 each time, so every flake falls at the same speed, but at a different angle
The third [4] is the random radius among 4 to 6, that will be shrinked each time and when o it will be deleted.
Let’s see it in the code.
Initial position of the snow flake
Let it snow… and rain
This is an improved version of the code, that now has also rain together with the snow.
import pygame import random import sys pygame.mixer.init() pygame.mixer.music.load("snow.mp3") FPS = 30 class Particle: "Makes particles to appear on the screen" def __init__(self): "Setting up screen, clock and loading images" pygame.init() # the two main surfaces self.screen = pygame.display.set_mode((800, 600), pygame.RESIZABLE) self.new_surface = pygame.Surface((800, 600)) self.frame_rate = pygame.time.Clock().tick # loading images for the script self.bg = pygame.image.load("snow6.png").convert() self.cloud = pygame.image.load("cloud.png") self.fg = pygame.image.load("snow7.png") self.snow_flakes_list = [] self.rain_drops_list = [] self.resize = 0 def update(self): "How to quit the window" self.frame_rate(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: self.run = False if event.type == pygame.VIDEORESIZE: self.resize = 1 self.w, self.h = event.w, event.h self.images_display() def images_display(self): "Make snow fall down - blitting images and calling the flake generator" self.new_surface.blit(self.bg, (0, 80)) self.snow_flakes_generator() # self.new_surface.blit(self.cloud, (-110,-100)) self.new_surface.blit(self.cloud, (-50, 290)) self.new_surface.blit(self.cloud, (450, 290)) self.new_surface.blit(self.fg, (0, 0)) if self.resize: self.screen.blit(pygame.transform.scale(self.new_surface, (self.w, self.h)), (0, 0)) else: self.screen.blit(self.new_surface, (0, 0)) pygame.display.flip() def mainloop(self): "A call to the self.update method to run stuffs" # Start the mp3 loaded at the beginning pygame.mixer.music.play() self.run = True while self.run: run = self.update() pygame.quit() exit() # the surface with the snow as a background def generate_one_particle(self, dim): direction = [random_pos(), random.randint(30,50)] # direction of x and next y pos incremented of 0.01 # change the 2 to change the way the snow flake falls angle_vel = [random.randint(0, 20) / 10 - 1, 2] radius = random.randint(4, 6) if dim == 4: angle_vel = [0, 6] radius = 1 return [direction, angle_vel, radius] def snow_flakes_generator(self): "circles move from random start position at the top until bottom and the disappear" self.snow() self.rain() def snow(self): self.snow_flakes_list.append(self.generate_one_particle(6)) self.falling_elements(self.snow_flakes_list) def rain(self): for drop in range(15): # 5 drops for frame self.rain_drops_list.append(self.generate_one_particle(4)) self.falling_elements(self.rain_drops_list) def falling_elements(self, elements_list): # Every particle moves... if snow_flakes_list[2] (the radius) is >= than 0 it is removed for particle in elements_list[:]: # parameters for new position (aka speed) and shrinking direction = particle[1][0] # random direction fixed velocity = particle[1][1] # how fast the flake falls gravity = 0.01 # how fast it falls melting = 0.005 # how fast it shrinks # DIRECTION particle[0][0] += direction # increase the x position of an angle (to the right or left) particle[0][1] += velocity # the y movement going down speed fixed 2 # but it is increased of 0.01 down here, so it goes down at the same speed particle[2] -= melting # the snowflake shriks particle[1][1] += gravity # * random.randint(-3, 6) # increase down speed a bit if particle[0][1] > 330: # when the radius is 0 it is removed, so we do not see it anymore and it's not in the memory elements_list.remove(particle) # draws a circle on the screen white, at x y corrds and with a ray of particle[2] for particle in elements_list: pos = particle[0][0] speed = particle[0][1] radius = particle[2] # circle: surface, color, pos, radius pygame.draw.circle( self.new_surface, (255, 255, 255), # color ( round(pos), # Pos x, y round(speed)), # direction / speed round(radius)) # radius def random_pos(): " to make a flame like snow_flakes_list [150, 20] # flame, so that all circles with start at the same point" return random.randint(30, 800) # return 150 fx = Particle() fx.mainloop()
Github repository for particles effect with assets
I added also sounds. Download this script and the assets here.
Another article on particles.
Subscribe to the newsletter for updates
Tkinter templates
My youtube channel
Twitter: @pythonprogrammi - python_pygame