1, Overall concept combing
In this article, the code example of python fireworks effect is compiled for you. Friends who are interested in this can learn and refer to it.
Friends who knock code every day, have you ever thought that code can also become very cool and romantic? Today, I'll teach you to simulate the blooming fireworks with Python. After work, you can also let the program set off a fireworks show for yourself at any time.
This interesting small project is not complicated. It only needs a little visualization skills, more than 100 lines of Python code and Tkinter library. Finally, we can achieve the following results:
After learning this tutorial, you can also make such a fireworks show.
2, Basics: designing fireworks with Python and Tkinter
Our whole idea is relatively simple.
As shown in the figure above, we simulate the explosion effect by splitting a particle on the picture into X particles. Particles "expand", meaning they move at a constant speed and at equal angles to each other. In this way, we can simulate the picture of fireworks blooming in the form of an outward expanding circle. After a certain period of time, the particles will enter the "free fall" stage, that is, due to gravity, they begin to fall to the ground, just like fireworks that bloom and go out.
Basics: designing fireworks with Python and Tkinter
There is no longer a brain to throw out all the mathematical knowledge. We talk about theory while writing code. First of all, make sure you have installed and imported Tkinter, which is the standard GUI Library of Python. It is widely used in various projects and program development. Using Tkinter in Python can quickly create GUI applications
Basics: Design fireworks in Python and Tkinter.
import tkinter as tk from PIL import Image, ImageTk from time import time, sleep from random import choice, uniform, randint from math import sin, cos, radians
In addition to Tkinter, in order to make the interface have a beautiful background, we also import PIL for image processing and other packages, such as time, random and math. They can make it easier for us to control the trajectory of fireworks particles.
The basic settings of Tkinter application are as follows:
root = tk.Tk()
In order to initialize Tkinter, we must create a Tk() root widget, which is a window with a title bar and other decorations provided by the window manager. The root part must be created before we create other widgets, and there can only be one root part.
w = tk.Label(root, text="Hello Tkinter!")
This line of code contains the Label part. The first parameter in the Label call is the name of the parent window, which is the "root" we use here. The keyword parameter "text" indicates the displayed text content. You can also call other widgets: Button, Canvas, etc.
w.pack() root.mainloop()
The next two lines of code are important. The packaging method here is to tell Tkinter to resize the window to fit the widget used. The window is closed until we enter the Tkinter event loop Only appears when mainloop() is called. The script will stay in the event loop until we close the window.
Translate fireworks into code
Now let's design an object to represent each particle in the fireworks event. Each particle has some important attributes that govern its appearance and movement: size, color, position, speed, and so on.
''' particles class Particles are randomly generated in the air, turn into a circle, fall and disappear attribute: - id: Particle id - x, y: Coordinates of particles - vx, vy: Speed of change in coordinates - total: total - age: Duration of particle existence - color: colour - cv: canvas - lifespan: Maximum duration ''' class part: def __init__(self, cv, idx, total, explosion_speed, x=0., y=0., vx = 0., vy = 0., size=2., color = 'red', lifespan = 2, **kwargs): self.id = idx self.x = x self.y = y self.initial_speed = explosion_speed self.vx = vx self.vy = vy self.total = total self.age = 0self.color = color self.cv = cv self.cid = self.cv.create_oval( x - size, y - size, x + size, y + size, fill=self.color) self.lifespan = lifespan
If we go back to the original idea, we will realize that we must ensure that all particles in each fireworks bloom must go through three different stages, namely "expansion", "falling" and "disappearance". So we add some motion functions to the particle class, as shown below:
''' def update(self, dt): # Particle expansion if self alive() and self. expand(): move_x = cos(radians(self.id*360/self.total))*self.initial_speed move_y = sin(radians(self.id*360/self.total))*self.initial_speed self.vx = move_x/(float(dt)*1000) self.vy = move_y/(float(dt)*1000) self.cv.move(self.cid, move_x, move_y) # Fall with free fall elif self.alive(): move_x = cos(radians(self.id*360/self.total)) # we technically don't need to update x, y because move will do the job self.cv.move(self.cid, self.vx + move_x, self.vy+GRAVITY*dt) self.vy += GRAVITY*dt # If the particle's life cycle has passed, remove it elif self.cid is not None: cv.delete(self.cid) self.cid = None
Of course, this also means that we must define how long each particle blooms and falls. In this part, we need to try more parameters to achieve the best visual effect.
# Defines the time frame for the inflation effect def expand (self): return self.age <= 1.2 # Check whether the particles are still in the life cycle def alive(self): return self.age <= self.lifespan
3, Using Tkinter simulation
Now we conceptualize the movement of particles, but obviously, a fireworks can't have only one particle, and a fireworks show can't have only one fireworks. Our next step is to let Python and Tkinter continuously "emit" particles into the sky in a way we can control.
Here, we need to upgrade from operating one particle to displaying multiple fireworks and multiple particles in each fireworks on the screen.
Our solution is as follows: create a list, and each sub list is a fireworks, which contains a list of particles. The examples in each list have the same X and Y coordinates, size, color and initial speed.
numb_explode = randint(6,10) # Create a list of all particles that simulate a fireworks bloom for point in range(numb_explode): objects = [] x_cordi = randint(50,550) y_cordi = randint(50, 150) size = uniform (0.5,3) color = choice(colors) explosion_speed = uniform(0.2, 1) total_particles = randint(10,50) for i in range(1,total_particles): r = part(cv, idx = i, total = total_particles, explosion_speed = explosion_speed, x = x_cordi, y = y_cordi, color=color, size = size, lifespan = uniform(0.6,1.75)) objects.append(r) explode_points.append(objects)
Our next step is to ensure that the particle's attributes are updated regularly. Here, we set the particles to update their state every 0.01 seconds and stop updating after 1.8 seconds (which means that the existence time of each particle is 1.6 seconds, of which 1.2 seconds is in the "blooming" state, 0.4 seconds is in the "falling" state, and 0.2 seconds is in the edge state before Tkinter completely removes it).
total_time = .0 # Keep updated within 1.8 second time frame while total_time < 1.8: sleep(0.01) tnew = time() t, dt = tnew, tnew - t for point in explode_points: for part in point: part.update(dt) cv.update() total_time += dt
Now, we just need to combine the last two gist s into a function that can be called by Tkinter, and call it simulate(). This function will display all data items and update the properties of each data item according to the time we set. In our main code, we will call this function with an alarm processing module after(), and after() will wait for a certain time before calling the function.
We set Tkinter to wait for 100 units (1 second) and then call simulate.
if __name__ == '__main__': root = tk.Tk() cv = tk.Canvas(root, height=600, width=600) # Draw a black background cv.create_rectangle(0, 0, 600, 600, fill="black") cv.pack() root.protocol("WM_DELETE_WINDOW", close) # stimulate() is not called until 1 second later root.after(100, simulate, cv) root.mainloop()
OK, so we put on a fireworks show with Python code:
This article is only a simple version. After getting more familiar with Tkinter, you can also add more color and more beautiful background photos to let the code bloom more beautiful fireworks for you!
4, All codes
import tkinter as tk from PIL import Image, ImageTk from time import time, sleep from random import choice, uniform, randint from math import sin, cos, radians # Simulated gravity GRAVITY = 0.05 # Color options (random or sequential) colors = ['red', 'blue', 'yellow', 'white', 'green', 'orange', 'purple', 'seagreen', 'indigo', 'cornflowerblue'] ''' particles class Particles are randomly generated in the air, turn into a circle, fall and disappear attribute: - id: Particle id - x, y: Coordinates of particles - vx, vy: Speed of change in coordinates - total: total - age: Duration of particle existence - color: colour - cv: canvas - lifespan: Maximum duration ''' class Particle: def __init__(self, cv, idx, total, explosion_speed, x=0., y=0., vx=0., vy=0., size=2., color='red', lifespan=2, **kwargs): self.id = idx self.x = x self.y = y self.initial_speed = explosion_speed self.vx = vx self.vy = vy self.total = total self.age = 0self.color = color self.cv = cv self.cid = self.cv.create_oval( x - size, y - size, x + size, y + size, fill=self.color) self.lifespan = lifespan def update(self, dt): self.age += dt # Particle range expansion if self.alive() and self.expand(): move_x = cos(radians(self.id * 360 / self.total)) * self.initial_speed move_y = sin(radians(self.id * 360 / self.total)) * self.initial_speed self.cv.move(self.cid, move_x, move_y) self.vx = move_x / (float(dt) * 1000) # Fall with free fall elif self.alive(): move_x = cos(radians(self.id * 360 / self.total)) # we technically don't need to update x, y because move will do the job self.cv.move(self.cid, self.vx + move_x, self.vy + GRAVITY * dt) self.vy += GRAVITY * dt # Remove particles that exceed the maximum duration elif self.cid is not None: cv.delete(self.cid) self.cid = None # Expanded time def expand (self): return self.age <= 1.2 # Is the particle within the maximum lifetime def alive(self): return self.age <= self.lifespan ''' The loop call keeps going ''' def simulate(cv): t = time() explode_points = [] wait_time = randint(10, 100) numb_explode = randint(6, 10) # Create a two-dimensional list of all particles expanded at the same time for point in range(numb_explode): objects = [] x_cordi = randint(50, 550) y_cordi = randint(50, 150) speed = uniform(0.5, 1.5) size = uniform(0.5, 3) color = choice(colors) explosion_speed = uniform(0.2, 1) total_particles = randint(10, 50) for i in range(1, total_particles): r = Particle(cv, idx=i, total=total_particles, explosion_speed=explosion_speed, x=x_cordi, y=y_cordi, vx=speed, vy=speed, color=color, size=size, lifespan=uniform(0.6, 1.75)) objects.append(r) explode_points.append(objects) total_time = .0 # Continuously expanded within 1.8s while total_time < 1.8: sleep(0.01) tnew = time() t, dt = tnew, tnew - t for point in explode_points: for item in point: item.update(dt) cv.update() total_time += dt # Loop call root.after(wait_time, simulate, cv) def close(*ignore): """Exit the program and close the window""" global root root.quit() if __name__ == '__main__': root = tk.Tk() cv = tk.Canvas(root, height=400, width=600) # Choosing a nice background will make the effect more amazing! image = Image.open("./image.jpg") photo = ImageTk.PhotoImage(image) cv.create_image(0, 0, image=photo, anchor='nw') cv.pack() root.protocol("WM_DELETE_WINDOW", close) root.after(100, simulate, cv) root.mainloop()
References link: python fireworks source code