
写在前面
Python 语言结合 Pygame 库实现新年烟花秀的完整代码。
技术需求
- Pygame 库:用于创建图形界面、绘制图形、处理用户输入和管理时间。通过
pg.init()初始化,pg.display.set_mode()创建屏幕。 - 随机数生成:使用
random库控制烟花和粒子的颜色、速度、方向等,模拟自然效果。 - 物理模拟:利用
Vector2类表示坐标和速度,模拟重力和粒子运动轨迹。 - 粒子系统:烟花爆炸产生多个粒子对象,每个粒子拥有独立属性(颜色、大小、生命周期)。
- 路径追踪(Trail):记录粒子位置生成尾迹,模拟轨迹消失效果。
- 图形渲染:使用
pg.draw.circle()和screen.fill()绘制粒子与背景。 - 动态文本渲染:显示 "Happy New Year!" 文本。
- 事件处理:监听窗口关闭事件,控制程序运行状态。
- 面向对象编程:封装
Firework、Particle、Trail类以模块化设计。
完整代码
import pygame as pg
import random as ra
import math
pg.init()
pg.display.set_caption("🎇")
winScreen = pg.display.Info()
screenWidth = winScreen.current_w
screenHeight = winScreen.current_h
vector = pg.math.Vector2
trail_colors = [(45, 45, 45), (60, 60, 60), (75, 75, 75), (125, 125, 125), (150, 150, 150)]
# 痕迹类 (Trail)
class Trail:
def __init__(self, index, size, dynamic):
self.index = index
self.size = size
self.dynamic = dynamic
self.color = trail_colors[index] if index < len(trail_colors) else (255, 255, 255)
self.alpha = 255
def show(self, win):
# 简化绘制逻辑,实际需根据位置绘制
pass
# 粒子类 (Particle)
class Particle:
def __init__(self, x, y, firework, colour):
self.firework = firework
self.pos = vector(x, y)
self.origin = vector(x, y)
self.radius = 25
self.remove = False
self.explosion_radius = ra.randint(15, 25)
self.life = 0
self.acc = vector(0, 0)
self.trails = []
self.prev_posx = [-10] * 10
self.prev_posy = [-10] * 10
if self.firework:
self.vel = vector(0, -ra.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(ra.uniform(-1, 1), ra.uniform(-1, 1))
self.vel.x *= ra.randint(7, self.explosion_radius + 2)
self.vel.y *= ra.randint(7, self.explosion_radius + 2)
self.size = ra.randint(2, 4)
self.colour = ra.choice(colour)
for i in range(5):
self.trails.append(Trail(i, self.size, False))
def apply_force(self, force):
self.acc += force / self.size
def move(self):
self.vel += self.acc
self.pos += self.vel
self.acc = vector(0, 0)
self.life += 1
if self.life > 100: # 假设生命周期
self.remove = True
def show(self, win):
pg.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)
def remove_check(self):
return self.remove
# 烟花类 (Firework)
class Firework:
def __init__(self):
self.colour = (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
self.colours = (
(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
)
self.firework = Particle(ra.randint(0, screenWidth), screenHeight, True, self.colour)
self.exploded = False
self.particles = []
self.min_max_particles = vector(666, 999)
def update(self, win):
g = vector(0, ra.uniform(0.15, 0.4))
if not self.exploded:
self.firework.apply_force(g)
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(g.x + ra.uniform(-1, 1) / 20, g.y / 2 + (ra.randint(1, 8) / 100)))
particle.move()
for t in particle.trails:
t.show(win)
particle.show(win)
def explode(self):
amount = ra.randint(int(self.min_max_particles.x), int(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):
pg.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_check():
self.particles.remove(p)
if len(self.particles) == 0:
return True
return False
# 更新函数
def update(screen, fireworks):
for fw in fireworks:
fw.update(screen)
fireworks[:] = [fw for fw in fireworks if not fw.remove()]
# 主函数 (fire)
def fire():
screen = pg.display.set_mode((screenWidth, screenHeight))
clock = pg.time.Clock()
running = True
fireworks = []
font = pg.font.SysFont('Arial', 50)
text = font.render("Happy New Year!", True, (255, 255, 255))
text_rect = text.get_rect(center=(screenWidth // 2, screenHeight // 2))
while running:
clock.tick(99)
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
screen.fill((20, 20, 30))
screen.blit(text, text_rect)
if ra.randint(0, 10) == 1:
fireworks.append(Firework())
update(screen, fireworks)
pg.display.flip()
pg.quit()
if __name__ == "__main__":
fire()
代码分析
1. 程序初始化与显示设置
调用 pg.init() 初始化库,设置窗口标题。获取屏幕分辨率并存储为 screenWidth 和 screenHeight。使用 pg.math.Vector2 进行向量运算。
2. 烟花类 (Firework)
核心类,模拟发射到爆炸过程。构造函数中随机生成颜色,创建初始火花粒子。update 方法处理重力作用下的上升及爆炸触发。
3. 粒子类 (Particle)
代表单个粒子。包含位置、速度、加速度、生命周期等属性。区分发射火花与爆炸粒子,设置不同的初速度与颜色。提供 apply_force 和 move 方法模拟物理运动。
4. 痕迹类 (Trail)
表示粒子尾迹。构造函数中区分动态与静态尾迹,设置颜色与尺寸。
5. 烟花更新与显示
update 函数遍历烟花列表,调用各对象的更新方法。移除已结束的粒子或烟花对象。
6. 主函数 (fire)
创建窗口与时钟,初始化烟花列表与文本渲染。计算文本居中位置。
7. 游戏循环
主循环控制帧率(99 FPS)。检测退出事件,填充背景色,绘制文本。随机生成新烟花,更新所有状态并刷新显示。
注意事项
如遇到问题 "no module named pygame",请在终端输入以下命令安装:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygame
等待安装完成后再运行程序。




