文章目录
- 一、前言
- 二、实现步骤
- 1.前期准备
- 2.部分代码
- 2.1 窗口设置
- 2.2 烟花类 Firework
- 2.3 粒子类 Particle
- 2.4 轨迹类 Trail
- 2.5 更新函数
- 2.6 导入音频
- 2.7 显示元旦快乐
- 2.8 Esc键结束
- 3.完整代码(详细注释)
- 4.视频效果
- 5.可执行文件
- 三、总结
一、前言
2023已经过去,我们即将迎来2024年的元旦节。在这个值得庆祝的日子里,许多人都会想要为自己或者与亲朋好友共同创造一些难忘的瞬间。而作为一名Python初学者,也可以不出门,在家中利用所学编写一个元旦烟花秀,为元旦节增添一份喜庆的气氛。通过编写这个小程序,你不仅可以锻炼自己的编程能力,还可以在其中感受到自己的创造力和乐趣。
在本篇博客中,我们将介绍如何使用Python编写一个简单的元旦烟花秀程序,并帮助大家实现自己的创意和想象。
二、实现步骤
1.前期准备
安装python和pygame,PyCharm(IDE可不安装)和pyinstaller(打包可不安装)
安装请参考以下教程:
Python新手上路:“用Python和Pygame创造你的流星雨”
一键启动Python世界:PyCharm安装全攻略与pyinstaller魔法转换
2.部分代码
2.1 窗口设置
以下示例代码获取当前屏幕的分辨率,并将窗口尺寸设置为全屏分辨率。
示例代码如下:
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
2.2 烟花类 Firework
以下示例代码定义了烟花的属性和行为,包括烟花的颜色、位置、是否爆炸以及爆炸后产生的粒子等。
示例代码如下:
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
2.3 粒子类 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 = 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坐标
2.4 轨迹类 Trail
以下示例代码定义了烟花和粒子的尾迹效果,包括尾迹的位置、颜色和大小等。
- init(self, n, size, dynamic):构造方法,初始化烟花粒子尾迹的属性。其中 n 表示烟花轨迹在轨迹数组中的位置,size 表示尾迹的初始大小,dynamic 是一个布尔值,表示轨迹是否是动态的。
- get_pos(self, x, y):用于设置尾迹的位置,接收 x 和 y 作为坐标参数。
- show(self, win):用于在显示窗口中绘制尾迹。使用 pygame.draw.circle() 绘制一个圆形轨迹点,颜色由 self.colour 指定,位置由 self.pos 的坐标确定,大小由 self.size 决定。
示例代码如下:
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 # 设置轨迹点的大小为原始大小 - 2if self.size < 0: # 如果计算后的轨迹点大小小于0self.size = 0 # 设置轨迹点为0def 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) # 绘制一个圆形轨迹点,使用指定的颜色、位置和大小
2.5 更新函数
以下示例代码用于更新烟花和粒子的状态,并在窗口上绘制它们的轨迹和形状。
示例代码如下:
#实时更新和展示烟花效果
def update(win, fireworks): # 用于更新烟花的状态并进行绘制for fw in fireworks: # 对于烟花效果数组fw.update(win) # 更新烟花效果的状态if fw.remove(): # 判断烟花效果是否达到移除条件fireworks.remove(fw) # 移除pygame.display.update() # 刷新显示窗口,将更新后的烟花效果显示出来
2.6 导入音频
以下示例代码,我们假设有一个名为"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()
2.7 显示元旦快乐
以下示例代码展示了如何加载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)) # 将文本绘制到窗口上
2.8 Esc键结束
以下示例代码展示了一个主循环,该循环会不断检测键盘按键事件,如果按下的是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,表示退出主循环,从而退出程序。
3.完整代码(详细注释)
总体来说,该程序使用 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_heighttrail_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 Trueelse:return Falseclass 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 # 设置烟花粒子的大小为4self.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 = Trueself.decay() # 衰减处理,逐渐降低粒子的半径和透明度,模拟粒子的消失过程self.trail_update() # 更新粒子的尾迹效果self.life += 1 # 粒子的生命周期加1def 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: # 概率为0self.remove = True # 移除粒子elif self.life > 80: # 检查粒子的生命周期是否超过设置值ran = randint(0, 5) # 衰减事件的概率范围减少if ran == 0: # 概率为0self.remove = True # 移除粒子# 更新粒子效果中的轨迹信息,它将当前的粒子位置信息插入位置列表的开头,然后根据轨迹类型选择正确的位置信号,并更新轨迹对象的位置. def trail_update(self): # 用于更新粒子的尾迹位置self.prev_posx.pop() # 移除最后一个元素xself.prev_posx.insert(0, int(self.pos.x)) # 插入到表头self.prev_posy.pop() # 移除最后一个元素yself.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 # 设置轨迹点的大小为原始大小 - 2if self.size < 0: # 如果计算后的轨迹点大小小于0self.size = 0 # 设置轨迹点为0def 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() # 退出pygamequit() # 退出程序main() # 调用main函数来启动程序
4.视频效果
该视频附带真实烟花音效,有点吵,不喜欢也可以自行去掉。
New Year‘s Day fireworks show
5.可执行文件
如果是还没有安装python环境和软件的小伙伴也想看到美丽的元旦烟花秀,可以下载资源或者直接私信我,我已经打包好了可执行文件,直接双击就能运行,无需下载python环境。
三、总结
本文主要介绍了如何使用Python编写一个简单的元旦烟花秀程序。通过本文的学习,我们可以学习到如何使用Python中的random模块生成随机的烟花效果,并利用pygame库实现动态显示。同时,我们还介绍了如何为烟花效果添加音效,并将整个程序打包成可执行文件。总之,这篇文章为Python初学者提供了一个实践项目,让大家在编程的过程中感受到创造的乐趣和实现想象的快感。
感谢你的观看,谢谢!