用Python绘制炫酷烟花效果:Pygame实现烟花动画 | 南锋

南锋

南奔万里空,脱死锋镝余

用Python绘制炫酷烟花效果:Pygame实现烟花动画

还有几个小时就2023年了,用python写一个烟花代码,庆祝下~

注意:代码中需要用到字体文件,需要自己修改字体文件路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import pygame
from random import randint, uniform, choice
import math

vector = pygame.math.Vector2
gravity = vector(0, 0.3)
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 700


trail_colours = [(45, 45, 45), (60, 60, 60), (75, 75, 75), (125, 125, 125), (150, 150, 150)]
dynamic_offset = 1
static_offset = 3

class Firework:
def __init__(self):
self.colour = (randint(0, 255), randint(0, 255), randint(0, 255))
self.colours = (
(randint(0, 255), randint(0, 255), randint(0, 255)),
(randint(0, 255), randint(0, 255), randint(0, 255)),
(randint(0, 255), randint(0, 255), randint(0, 255)))
self.firework = Particle(randint(0, DISPLAY_WIDTH), DISPLAY_HEIGHT, True,
self.colour) # Creates the firework particle
self.exploded = False
self.particles = []
self.min_max_particles = vector(100, 225)

def update(self, win): # called every frame
if not self.exploded:
self.firework.apply_force(gravity)
self.firework.move()
for tf in self.firework.trails:
tf.show(win)

self.show(win)

if self.firework.vel.y >= 0:
self.exploded = True
self.explode()
else:
for particle in self.particles:
particle.apply_force(vector(gravity.x + uniform(-1, 1) / 20, gravity.y / 2 + (randint(1, 8) / 100)))
particle.move()
for t in particle.trails:
t.show(win)
particle.show(win)

def explode(self):

amount = randint(self.min_max_particles.x, self.min_max_particles.y)
for i in range(amount):
self.particles.append(Particle(self.firework.pos.x, self.firework.pos.y, False, self.colours))

def show(self, win):
pygame.draw.circle(win, self.colour, (int(self.firework.pos.x), int(self.firework.pos.y)), self.firework.size)

def remove(self):
if self.exploded:
for p in self.particles:
if p.remove is True:
self.particles.remove(p)

if len(self.particles) == 0:
return True
else:
return False


class Particle:
def __init__(self, x, y, firework, colour):
self.firework = firework
self.pos = vector(x, y)
self.origin = vector(x, y)
self.radius = 20
self.remove = False
self.explosion_radius = randint(5, 18)
self.life = 0
self.acc = vector(0, 0)
# trail variables
self.trails = [] # stores the particles trail objects
self.prev_posx = [-10] * 10 # stores the 10 last positions
self.prev_posy = [-10] * 10 # stores the 10 last positions

if self.firework:
self.vel = vector(0, -randint(17, 20))
self.size = 5
self.colour = colour
for i in range(5):
self.trails.append(Trail(i, self.size, True))
else:
self.vel = vector(uniform(-1, 1), uniform(-1, 1))
self.vel.x *= randint(7, self.explosion_radius + 2)
self.vel.y *= randint(7, self.explosion_radius + 2)

self.size = randint(2, 4)
self.colour = choice(colour)

for i in range(5):
self.trails.append(Trail(i, self.size, False))

def apply_force(self, force):
self.acc += force

def move(self):
if not self.firework:
self.vel.x *= 0.8
self.vel.y *= 0.8
self.vel += self.acc
self.pos += self.vel
self.acc *= 0

if self.life == 0 and not self.firework: # check if particle is outside explosion radius
distance = math.sqrt((self.pos.x - self.origin.x) ** 2 + (self.pos.y - self.origin.y) ** 2)
if distance > self.explosion_radius:
self.remove = True

self.decay()

self.trail_update()

self.life += 1

def show(self, win):
pygame.draw.circle(win, (self.colour[0], self.colour[1], self.colour[2], 0), (int(self.pos.x), int(self.pos.y)),
self.size)

def decay(self): # random decay of the particles
if 50 > self.life > 10: # early stage their is a small chance of decay
ran = randint(0, 30)
if ran == 0:
self.remove = True
elif self.life > 50:
ran = randint(0, 5)
if ran == 0:
self.remove = True

def trail_update(self):
self.prev_posx.pop()
self.prev_posx.insert(0, int(self.pos.x))
self.prev_posy.pop()
self.prev_posy.insert(0, int(self.pos.y))

for n, t in enumerate(self.trails):
if t.dynamic:
t.get_pos(self.prev_posx[n + dynamic_offset], self.prev_posy[n + dynamic_offset])
else:
t.get_pos(self.prev_posx[n + static_offset], self.prev_posy[n + static_offset])


class Trail:
def __init__(self, n, size, dynamic):
self.pos_in_line = n
self.pos = vector(-10, -10)
self.dynamic = dynamic

if self.dynamic:
self.colour = trail_colours[n]
self.size = int(size - n / 2)
else:
self.colour = (255, 255, 200)
self.size = size - 2
if self.size < 0:
self.size = 0

def get_pos(self, x, y):
self.pos = vector(x, y)

def show(self, win):
pygame.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)


def update(win, fireworks):
for fw in fireworks:
fw.update(win)
if fw.remove():
fireworks.remove(fw)

pygame.display.update()


def main():
pygame.init()
pygame.font.init()
pygame.display.set_caption("元旦烟花")
background = pygame.image.load("img/1.png")
myfont = pygame.font.Font("img/font.ttf",80)
myfont1 = pygame.font.Font("img/font.ttf", 30)

testsurface = myfont.render("元旦节快乐",False,(251, 59, 85))
# pygame.image.load("")
win = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
# win.blit(background)
clock = pygame.time.Clock()

fireworks = [Firework() for i in range(2)] # create the first fireworks
running = True

while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN: # Change game speed with number keys
if event.key == pygame.K_1: # 按下 1
fireworks.append(Firework())
if event.key == pygame.K_2: # 按下 2 加入10个烟花
for i in range(10):
fireworks.append(Firework())
win.fill((20, 20, 30)) # draw background
win.blit(background,(800,800))
win.blit(testsurface,(200,30))
if randint(0, 20) == 1: # create new firework
fireworks.append(Firework())
update(win, fireworks)
pygame.quit()
quit()
main()
+