2023已经过去,我们即将迎来2024年的元旦节。在这个值得庆祝的日子里,许多人都会想要为自己或者与亲朋好友共同创造一些难忘的瞬间。而作为一名Python初学者,也可以不出门,在家中利用所学编写一个元旦烟花秀,为元旦节增添一份喜庆的气氛。通过编写这个小程序,你不仅可以锻炼自己的编程能力,还可以在其中感受到自己的创造力和乐趣。
在本篇博客中,我们将介绍如何使用Python编写一个简单的元旦烟花秀程序,并帮助大家实现自己的创意和想象。
安装python和pygame,PyCharm(IDE可不安装)和pyinstaller(打包可不安装)
安装请参考以下教程:
Python新手上路:“用Python和Pygame创造你的流星雨”
一键启动Python世界:PyCharm安装全攻略与pyinstaller魔法转换
以下示例代码获取当前屏幕的分辨率,并将窗口尺寸设置为全屏分辨率。
示例代码如下:
pygame.init() # 初始化pygame库
#获取当前屏幕的分辨率
sceen_info = pygame.display.Info()
sceen_width = sceen_info.current_w
sceen_height = sceen_info.current_h
#设置窗口尺寸为屏幕分辨率
DISPLAY_WIDTH = sceen_width
DISPLAY_HEIGHT = sceen_height
win = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT)) # 创建指定大小的窗口,并赋值给变量win
以下示例代码定义了烟花的属性和行为,包括烟花的颜色、位置、是否爆炸以及爆炸后产生的粒子等。
示例代码如下:
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) # 初始化烟花的位置
self.exploded = False # 表示烟花是否已经爆炸
self.particles = [] # 空列表,用于储存烟花爆炸后生成的粒子
self.min_max_particles = vector(200, 255) # 定义烟花爆炸产生的粒子数量的范围 200-255
以下示例代码定义了烟花爆炸后产生的粒子的属性和行为,包括粒子的位置、速度、颜色、尾迹效果等。
示例代码如下:
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(20, 40) # 表示粒子爆炸时的扩散半径
self.life = 0 # 表示粒子的生命周期即存在时间
self.acc = vector(0, 0) # 表示粒子的加速度
self.trails = [] # 存储粒子的尾迹对象
self.prev_posx = [-10] * 10 # 储存粒子过去10个位置的x坐标
self.prev_posy = [-10] * 10 # 储存粒子过去10个位置的y坐标
以下示例代码定义了烟花和粒子的尾迹效果,包括尾迹的位置、颜色和大小等。
示例代码如下:
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 # 设置轨迹点的大小为原始大小 - 2
if self.size < 0: # 如果计算后的轨迹点大小小于0
self.size = 0 # 设置轨迹点为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() # 刷新显示窗口,将更新后的烟花效果显示出来
以下示例代码,我们假设有一个名为"firework.wav"的音频文件,然后使用pygame.mixer.Sound()加载该文件,并通过play()方法播放声音。这样就可以在烟花秀中添加音效了。请注意,在使用pygame.mixer.Sound()之前,需要先初始化pygame.mixer,即pygame.mixer.init()。这样才能正确地加载和播放声音文件。
示例代码如下:
# 初始化 Pygame 音频
pygame.mixer.init()
firework_sound = pygame.mixer.Sound("firework.wav")
# 播放声音
firework_sound.play()
以下示例代码展示了如何加载Windows自带的中文字体文件,并在窗口上显示“元旦快乐”的文本。其中msyh.ttc是微软雅黑字体文件的示例。
示例代码如下:
# 加载 Windows 自带的中文字体文件
font_path = "C:/Windows/Fonts/msyh.ttc"
pygame.font.init() # 初始化字体模块
# 在窗口上显示"元旦快乐"文本
font = pygame.font.Font(font_path, 100) # 设置字体和大小
# text = font.render("元旦快乐", True, (148, 0, 211)) # 创建文本对象
random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # 生成随机颜色
text = font.render("元旦快乐", True, random_color) # 创建文本对象并设置随机颜色
text_width, text_height = font.size("元旦快乐") # 获取文本的宽度和高度
text_x = (DISPLAY_WIDTH - text_width) // 2 # 计算文本放置的 x 坐标
text_y = (DISPLAY_HEIGHT - text_height) // 4 # 计算文本放置的 y 坐标
win.blit(text, (text_x, text_y)) # 将文本绘制到窗口上
以下示例代码展示了一个主循环,该循环会不断检测键盘按键事件,如果按下的是Esc键,则将标志变量running设置为False,从而退出主循环并结束程序。
示例代码如下:
while running: # 进入主循环,直到标志变量running为False时结束循环
for event in pygame.event.get(): # 遍历事件队列中的所有事件
if event.type == pygame.KEYDOWN: # 如果事件类型是KEYDOWN(即键盘按下事件)
if event.key == pygame.K_ESCAPE: # 检测按下的按键是否为Esc键
running = False # 将标志变量running设置为False,表示退出主循环,从而退出程序。
总体来说,该程序使用 Pygame 库实现了烟花动画效果,包括烟花的发射、爆炸和粒子效果,并在窗口上绘制出烟花的轨迹和形状。同时,程序还实现了在窗口中显示“元旦快乐”文本和播放烟花爆炸的声音效果。
代码如下(示例):
import math # 导入math模块(数学函数)
import pygame # 导入pygame模块
import os # 导入os模块
import random # 导入random模块(随机数)
import numpy as np #导入numpy库,用于进行数值计算和数组操作
from random import randint, uniform, choice # 从random库中导入randint、uniform、chioce函数
# 初始化 Pygame 音频
pygame.mixer.init()
firework_sound = pygame.mixer.Sound("firework.wav")
# 加载 Windows 自带的中文字体文件
font_path = "C:/Windows/Fonts/msyh.ttc"
vector = pygame.math.Vector2 #处理二维向量
gravity = vector(0, 0.2) #重力加速度,方向向下
pygame.init() # 初始化pygame库
#获取当前屏幕的分辨率
sceen_info = pygame.display.Info()
sceen_width = sceen_info.current_w
sceen_height = sceen_info.current_h
#设置窗口尺寸为屏幕分辨率
DISPLAY_WIDTH = sceen_width
DISPLAY_HEIGHT = sceen_height
trail_colours = [(45, 45, 45), (60, 60, 60), (75, 75, 75),
(125, 125, 125), (150, 150, 150)] # 烟花的尾迹颜色
dynamic_offset = 1 # 动态偏移
static_offset = 5 # 静态偏移
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) # 初始化烟花的位置
self.exploded = False # 表示烟花是否已经爆炸
self.particles = [] # 空列表,用于储存烟花爆炸后生成的粒子
self.min_max_particles = vector(200, 255) # 定义烟花爆炸产生的粒子数量的范围 200-255
# 焰火效果的更新函数,用于在每一帧更新焰花和粒子的位置,并在窗口上显示它们的轨迹和形状
def update(self, win): # 更新烟花的状态,参数win表示显示窗口
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: # 如果焰火的纵向加速度大于等于0,表示烟花达到顶点
self.exploded = True # 设置烟花爆炸
self.explode() # 触发爆炸效果
else: # 烟花已经爆炸
for particle in self.particles: # 对于每一个烟花粒子
particle.apply_force(
vector(gravity.x + uniform(-2, 2) / 50, gravity.y / 2 + (randint(1, 20) / 255))) # 施加随机力量(重力和额外随机力的作用)
particle.move() # 移动粒子的位置
for t in particle.trails: # 对于每一个粒子轨迹
t.show(win) # 在窗口上显示轨迹形状
particle.show(win) # 在窗口上显示粒子形状
def explode(self): # 用于烟花爆炸时生成粒子的过程
amount = 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)) # 传入爆炸发生位置的x和y坐标(即烟花的位置)
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(20, 40) # 表示粒子爆炸时的扩散半径
self.life = 0 # 表示粒子的生命周期即存在时间
self.acc = vector(0, 0) # 表示粒子的加速度
self.trails = [] # 存储粒子的尾迹对象
self.prev_posx = [-10] * 10 # 储存粒子过去10个位置的x坐标
self.prev_posy = [-10] * 10 # 储存粒子过去10个位置的y坐标
if self.firework: # 判断烟花状态是否爆炸
self.vel = vector(0, -randint(13, 18)) # 设置烟花的速度向量,使得烟花能够垂直向上发射
self.size = 4 # 设置烟花粒子的大小为4
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(10, self.explosion_radius + 2) # 模拟烟花爆炸时粒子的速度 水平方向
self.vel.y *= randint(10, self.explosion_radius + 2) # 模拟烟花爆炸时粒子的速度 垂直方向
self.size = randint(1, 5) # 设置烟花爆炸后产生的粒子的大小
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.85 # 模拟阻尼效果,进行减速
self.vel.y *= 0.85 # 模拟阻尼效果,进行减速
self.vel += self.acc # 更新粒子速度
self.pos += self.vel # 更新粒子位置
self.acc *= 0 # 粒子加速度清零
if self.life == 0 and not self.firework:
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 # 粒子的生命周期加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): # 用于模拟粒子的衰减效果
if 80 > self.life > 10: # 检查粒子的生命周期是否在指定范围内
ran = randint(0, 30) # 衰减事件的概率
if ran == 0: # 概率为0
self.remove = True # 移除粒子
elif self.life > 80: # 检查粒子的生命周期是否超过设置值
ran = randint(0, 5) # 衰减事件的概率范围减少
if ran == 0: # 概率为0
self.remove = True # 移除粒子
# 更新粒子效果中的轨迹信息,它将当前的粒子位置信息插入位置列表的开头,然后根据轨迹类型选择正确的位置信号,并更新轨迹对象的位置.
def trail_update(self): # 用于更新粒子的尾迹位置
self.prev_posx.pop() # 移除最后一个元素x
self.prev_posx.insert(0, int(self.pos.x)) # 插入到表头
self.prev_posy.pop() # 移除最后一个元素y
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 # 设置轨迹点的大小为原始大小 - 2
if self.size < 0: # 如果计算后的轨迹点大小小于0
self.size = 0 # 设置轨迹点为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库
pygame.font.init() # 初始化字体模块
pygame.display.set_caption("Firework in Pygame") # 设置窗口标题
win = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT)) # 创建指定大小的窗口,并赋值给变量win
fireworks = [Firework() for i in range(2)] # 创建包含两个Firework对象的列表,作为初始的烟花效果
running = True # 设置程序为运行状态
while running: # 进入主循环,直到标志变量running为False时结束循环
for event in pygame.event.get(): # 遍历事件队列中的所有事件
if event.type == pygame.KEYDOWN: # 如果事件类型是KEYDOWN(即键盘按下事件)
if event.key == pygame.K_ESCAPE: # 检测按下的按键是否为Esc键
running = False # 将标志变量running设置为False,表示退出主循环,从而退出程序。
win.fill((20, 20, 30)) # 用深蓝色填充窗口,作为背景色
if randint(0, 2) == 1: # 以一定概率创建新的烟花效果
fireworks.append(Firework())
# 在窗口上显示"元旦快乐"文本
font = pygame.font.Font(font_path, 100) # 设置字体和大小
# text = font.render("元旦快乐", True, (148, 0, 211)) # 创建文本对象
random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # 生成随机颜色
text = font.render("元旦快乐", True, random_color) # 创建文本对象并设置随机颜色
text_width, text_height = font.size("元旦快乐") # 获取文本的宽度和高度
text_x = (DISPLAY_WIDTH - text_width) // 2 # 计算文本放置的 x 坐标
text_y = (DISPLAY_HEIGHT - text_height) // 4 # 计算文本放置的 y 坐标
win.blit(text, (text_x, text_y)) # 将文本绘制到窗口上
# 播放声音
firework_sound.play()
update(win, fireworks) # 更新并展示当前所有的烟花效果
pygame.quit() # 退出pygame
quit() # 退出程序
main() # 调用main函数来启动程序
该视频附带真实烟花音效,有点吵,不喜欢也可以自行去掉。
New Year‘s Day fireworks show
如果是还没有安装python环境和软件的小伙伴也想看到美丽的元旦烟花秀,可以下载资源或者直接私信我,我已经打包好了可执行文件,直接双击就能运行,无需下载python环境。
本文主要介绍了如何使用Python编写一个简单的元旦烟花秀程序。通过本文的学习,我们可以学习到如何使用Python中的random模块生成随机的烟花效果,并利用pygame库实现动态显示。同时,我们还介绍了如何为烟花效果添加音效,并将整个程序打包成可执行文件。总之,这篇文章为Python初学者提供了一个实践项目,让大家在编程的过程中感受到创造的乐趣和实现想象的快感。
感谢你的观看,谢谢!