Use Python to write the most dazzling firework code on New Year’s Eve, a romantic firework show for straight men in science and engineering

Write in front

Have you ever thought that friends who type code every day can also become cool and romantic? Today, I will use Python to simulate the blooming fireworks. After work, you can also let the program set up a fireworks show for yourself at any time, and you can also please your girlfriend.

This interesting little project is not complicated, just a little visualization skills, more than 100 lines of Python code and the library Tkinter, and finally we can achieve the following effect:

Overall concept review

As shown above, our whole concept is relatively simple. Here, the explosion effect is simulated by splitting a particle on the screen into X number of particles. The particles “expand,” meaning they move at a constant speed and at equal angles to each other. This allows us to simulate the fireworks blooming as an outwardly expanding circle. After a certain amount of time, the particles enter a “free fall” phase, where they begin to fall to the ground due to gravity, like fireworks that bloom and then extinguish.

Basics: Designing Fireworks with Python and Tkinter

Here we no longer throw out all the mathematical knowledge in one brain, we write code and talk about theory. First, make sure you have installed and imported Tkinter, which is Python’s standard GUI library and is widely used in various projects and program development. Using Tkinter in Python can quickly create GUI applications.

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 import some other packages, such as time, random and math. They allow us to more easily control the trajectory of fireworks particles.

The basic setup for a Tkinter application is 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 widget must be created before we create other widgets, and there can only be one root widget.

w = tk.Label(root, text="Hello Tkinter!")

This line of code contains the Label widget. The first parameter in the Label call is the name of the parent window, which is the “root” we use here. The keyword argument “text” specifies the text content to display. You can also call other widgets: Button, Canvas, etc.

w. pack()
root. mainloop()

The next two lines of code are important. The packing method here is to tell Tkinter to resize the window to fit the widget used. The window doesn’t appear until we enter the Tkinter event loop, which is called by root.mainloop(). The script will stay in the event loop until we close the window.

Translate fireworks into code

Now we design an object that represents each particle in the firework event. Each particle will have some important properties that govern its appearance and movement: size, color, position, speed, etc.

particle class

Particles are randomly generated in the air, become a circle, fall, and disappear

Attributes:
    - id: the id of the particle
    - x, y: coordinates of the particle
    - vx, vy: velocity of change in coordinates
    - total: total number
    - age: how long the particle exists
    - color: color
    - cv: canvas
    - lifespan: maximum lifetime

   
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 and think about the original idea, we realize that we have to make sure that all the particles of each firework bloom have to go through 3 different stages, namely “inflate”, “fall” and “disappear”. So let’s add some more motion functions to the particle class, like so:

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 in 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 lifetime of the particle has expired, remove it
    elif self.cid is not None:
        cv.delete(self.cid)
        self.cid = None

Of course, this also means that we have to define how long each particle blooms and falls. This part requires us to try more parameters to achieve the best visual effect.

# Define the time frame of the expansion effect
def expand(self):
    return self. age <= 1.2

# Check if the particle is still alive
def alive(self):
    return self.age <= self.lifespan

Simulation with Tkinter

Now we conceptualize the movement of particles, but obviously, a firework cannot have only one particle, and a firework show cannot have only one firework. Our next step is to get Python and Tkinter to continuously “shoot” particles into the sky in a way that we can control.

At this point, we need to upgrade from manipulating one particle to displaying multiple fireworks and multiple particles in each firework on the screen.

Our solution is as follows: Create a list, each sub-list is a firework, which contains a list of particles. Each instance in the list has the same x,y coordinates, size, color, and initial velocity.

numb\_explode = randint(6,10)
# Create a list of all particles for all simulated fireworks blooms
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 properties are regularly updated. Here we set the particles to update their state every 0.01 seconds, and stop updating after 1.8 seconds (this means that each particle exists for 1.6 seconds, of which 1.2 seconds is the “blooming” state, 0.4 seconds is the “falling” state, 0.2 seconds is on the brink before Tkinter removes it completely).

total\_time = .0
# Keep updated on the 1.8 second timeframe
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 gists into one function that can be called by Tkinter, let’s 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 use an alarm processing module after() to call this function, and after() will wait for a certain period of time before calling the function.

Here we set Tkinter to wait for 100 units (1 second) before calling 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)
    # start calling stimulate() after 1 second
    root.after(100, simulate, cv)
    root. mainloop()

Ok, so we put a fireworks show with Python code:

This article is only a simple version. After you get more familiar with Tkinter, you can add more colorful and beautiful background photos, and let the code bloom more beautiful fireworks for you!

Here is the full code:

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

# simulate 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, become a circle, fall, and disappear

Attributes:
    - id: the id of the particle
    - x, y: coordinates of the particle
    - vx, vy: velocity of change in coordinates
    - total: total number
    - age: how long the particle exists
    - color: color
    - cv: canvas
    - lifespan: maximum lifetime

   


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 expanded
        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 in 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

    # time to expand
    def expand(self):
        return self. age <= 1.2

    # Whether the particle is 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 2D list of all particles that grows simultaneously
    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
    # Keep expanding 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, close the window"""
    global root
    root. quit()


if \_\_name\_\_ == \_\_main\_\_ :
    root = tk.Tk()
    cv = tk.Canvas(root, height=400, width=600)
    # Choosing a good-looking 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()

About Python technology reserves

Learning Python well is good whether it is employment or sideline business to make money, but to learn Python, you still need to have a study plan. Finally, everyone will share a full set of Python learning materials to help those who want to learn Python!

If you need friends, you can scan the QR code of CSDN official certification below on WeChat to get free 【Guaranteed 100% free】

1. Python Learning Outline

The technical points in all directions of Python are sorted out to form a summary of knowledge points in various fields. Its usefulness lies in that you can find corresponding learning resources according to the above knowledge points to ensure that you can learn more comprehensively.

2. Essential Python development tools

3. Introductory learning video

Fourth, actual combat cases

Optical theory is useless, you have to learn to follow along, and you have to do it yourself, so that you can apply what you have learned to practice. At this time, you can learn from some actual combat cases.

5. Python sideline part-time and full-time routes

[[CSDN spree: “Python part-time resources & amp; full set of learning materials” free sharing]](Safe link, click with confidence)