【走过路过,不要错过哦】python制作的浪漫烟花,非常烂漫

这是一个基于Python制作的烟花绽放动画程序,可以用于表白祝福。

一、设置一些画板的基本参数

# 初始化Pygame库。
pg.init()
# 设置窗口标题为“🎆 财源滚滚 🎆”。
pg.display.set_caption("🎆 财源滚滚 🎆")
# 获取当前屏幕信息并调整窗口高度以适应标题栏。
winScreen = pg.display.Info()
screenWidth = winScreen.current_w
screenHeight = winScreen.current_h - 66 
# 导入Pygame的二维向量类。
vector = pg.math.Vector2

# 增加颜色多样性
trail_colors = [
    (255, 0, 0), (255, 165, 0), (255, 255, 0), (0, 255, 0), (0, 0, 255),
    (128, 0, 128), (128, 0, 0), (0, 128, 0), (0, 128, 128), (0, 0, 128)
] + [(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)) for _ in range(50)]

二、初始化一个烟花对象

  • init 方法: 初始化烟花对象。
  • self.colour: 随机选择一种颜色。
  • self.firework: 创建一个 Particle 对象来表示烟花。
  • self.exploded: 标记烟花是否已爆炸。
  • self.particles: 存储爆炸后产生的粒子。
  • self.min_max_particles: 设置粒子数量的最小值和最大值。
  •     def __init__(self, initial_y=None):
            """
            初始化一个烟花对象。
    
            本构造函数设置了烟花的颜色、创建了一个粒子对象来表示烟花、设置烟花初始状态为未爆炸、
            并初始化一个双端队列来存储爆炸后产生的粒子。
            """
            # 随机选择一种颜色作为烟花的颜色
            self.colour = trail_colors[ra.randint(0, len(trail_colors)-1)]
    
            # 创建一个粒子对象来表示烟花,初始位置随机,带有指定颜色
            #self.firework = Particle(ra.randint(50, screenWidth), screenHeight, True, [self.colour])
            # 初始化烟花的位置,如果提供了initial_y则使用它,否则使用随机值
            self.firework = Particle(
                ra.randint(50, screenWidth) if initial_y is None else ra.randint(50, screenWidth),  # x坐标随机
                initial_y if initial_y is not None else screenHeight,  # 使用提供的y坐标或随机值
                True,
                [self.colour]
            )
            # 设置烟花初始状态为未爆炸
            self.exploded = False
    
            # 初始化一个双端队列来存储爆炸后产生的粒子
            self.particles = deque()
    
            # 设置粒子数量的最小值和最大值
            self.min_max_particles = vector(100, 300)
    

    三、更新烟花状态

  • update 方法: 更新烟花状态。
  • 如果烟花未爆炸,更新烟花的位置和状态。
  • 如果烟花需要移除,表示烟花已爆炸,生成一系列粒子。
  • 如果烟花已爆炸,更新所有粒子的状态,并移除需要删除的粒子。
  •     def update(self, win):
            """
            更新烟花状态。
    
            如果烟花尚未爆炸,则更新烟花的位置。当烟花需要移除时,表示烟花已爆炸,
            此时生成一系列粒子。如果烟花已经爆炸,则更新所有粒子的状态,并移除需要删除的粒子。
            当所有粒子都被移除后,重置烟花的爆炸状态。
    
            参数:
            win (Window): 游戏窗口对象,用于显示烟花和粒子。
    
            返回:
            无
            """
            if not self.exploded:
                # 更新烟花的位置和状态
                self.firework.update()
                # 当烟花需要移除时,表示烟花已爆炸
                if self.firework.remove:
                    self.exploded = True
                    # 生成随机数量的粒子
                    num_particles = ra.randint(int(self.min_max_particles.x), int(self.min_max_particles.y))
                    # 为每个粒子随机选择颜色
                    particle_colors = [trail_colors[ra.randint(0, len(trail_colors) - 1)] for _ in range(num_particles)]
                    # 创建并添加粒子到粒子列表中
                    for i in range(num_particles):
                        self.particles.append(Particle(self.firework.pos.x, self.firework.pos.y, False, [particle_colors[i]]))
            else:
                # 更新所有粒子的状态
                for p in list(self.particles):
                    p.update()
                    # 移除需要删除的粒子
                    if p.remove:
                        self.particles.remove(p)
                # 当所有粒子都被移除后,重置烟花的爆炸状态
                if not self.particles:
                    self.exploded = False  # Reset exploded state, though typically we wouldn't reset
    
    

    四、绘制烟火和粒子

  • draw 方法: 绘制烟火和粒子。
  • 如果烟花未爆炸,绘制烟火。
  • 无论烟花是否爆炸,都绘制所有粒子。
  •     def draw(self, win):
            """
            绘制烟火和粒子。
    
            如果烟火没有爆炸,则绘制烟火;否则,绘制所有粒子。
    
            参数:
            - win: 绘制烟火和粒子的窗口。
    
            返回值:
            无
            """
            # 检查烟火是否已经爆炸
            if not self.exploded:
                # 如果没有爆炸,绘制烟火
                self.firework.draw(win)
            # 无论烟火是否爆炸,都绘制所有粒子
            for p in self.particles:
                p.draw(win)
    

    五、定义 Particle 类

    初始化烟火对象的构造函数
  • init 方法: 初始化粒子对象。
  • self.firework: 标记是否为烟火。
  • self.pos 和 self.origin: 当前位置和初始位置。
  • self.radius: 烟火的初始半径或大小。
  • self.remove: 标记是否应该移除该粒子。
  • self.life: 粒子的生命周期计数器。
  • self.acc: 粒子的加速度,模拟重力效果。
  • self.size: 粒子的大小或半径。
  • self.vel: 根据是否是烟火,设置初始速度。
  • self.colour: 从传入的颜色列表中选择一个颜色作为粒子的颜色。
  • self.trail_length: 轨迹的长度。
  • self.trail_positions: 使用 deque 存储轨迹位置。
  •     def __init__(self, x, y, firework, colour_list):
            """
            初始化烟火对象的构造函数。
    
            参数:
            x (int): 烟火的初始x坐标。
            y (int): 烟火的初始y坐标。
            firework (bool): 表示是否为烟火。用于区分烟火和粒子的行为。
            colour_list (list): 包含可能的颜色的列表。粒子从中选择一种颜色。
    
            返回:
            None
            """
            self.firework = firework  # 是否为烟火
            self.pos = vector(x, y)  # 当前位置
            self.origin = vector(x, y)  # 初始位置,用于重置或计算轨迹
            self.radius = 60  # 烟火的初始半径或大小
            self.remove = False  # 标记是否应该移除该粒子
            self.life = 0  # 粒子的生命周期计数器
            self.acc = vector(0, 0.05)  # 粒子的加速度,模拟重力效果
            self.size = ra.randint(1, 2)  # 粒子的大小或半径
            self.vel = vector(
                ra.uniform(-2, 2) if not firework else 0,
                -ra.randint(20, 30) if firework else ra.uniform(-2, 2)
            )
            # 根据是否是烟火,设置初始速度。烟火有向上的速度,而粒子在水平方向有速度。
            self.colour = colour_list[0]  # 从传入的颜色列表中选择一个颜色作为粒子的颜色
            # 轨迹的长度,即轨迹中粒子的数量
            self.trail_length = 10
            # 使用deque存储轨迹位置,自动管理最大长度,用于渲染轨迹效果
            self.trail_positions = deque([(x, y)] * self.trail_length, maxlen=self.trail_length)
    
    
    更新烟花或粒子的状态
  • update 方法: 更新烟花或粒子的状态。
  • 更新速度和位置。
  • 如果是烟花,判断其是否达到最高点并决定是否移除。
  • 如果是粒子,增加其生命周期并判断是否达到生命终点。
  • 确保粒子不会超出屏幕边界。
  • 记录当前位置到轨迹列表。
  •     def update(self):
            """
            更新烟花或粒子的状态。
    
            该方法主要用于更新烟花或粒子的位置,判断其是否需要被移除,以及在其生命周期内追踪其轨迹。
            同时确保粒子不会超出屏幕边界。
            """
            # 更新速度和位置
            self.vel += self.acc
            self.pos += self.vel
    
            # 如果是烟花,判断其是否达到最高点并决定是否移除
            if self.firework:
                if self.pos.y < self.origin.y - 100:
                    self.remove = True
            else:
                # 如果是粒子,增加其生命周期并判断是否达到生命终点
                self.life += 1
                if self.life > 25:
                    self.remove = True
    
                # 确保粒子不会超出屏幕边界
                if self.pos.x < 0:
                    self.pos.x = 0
                elif self.pos.x > screenWidth:
                    self.pos.x = screenWidth-10
                if self.pos.y < 0:
                    self.pos.y = 0
                elif self.pos.y > screenHeight:
                    self.pos.y = screenHeight
    
            # 记录当前位置到轨迹列表,用于后续渲染轨迹
            self.trail_positions.appendleft((self.pos.x, self.pos.y))
    
    在指定的窗口上绘制当前对象
  • draw 方法: 在指定的窗口上绘制当前对象。
  • 绘制主要圆形部分。
  • 计算轨迹的透明度。
  • 绘制轨迹,每个轨迹点都是一个小圆点,具有计算出的透明度。
  •     def draw(self, win):
            """
            在指定的窗口上绘制当前对象。
    
            参数:
            - win: pygame窗口对象,用于绘制图形。
    
            此方法负责在给定的pygame窗口上绘制当前对象的主要圆形部分和其轨迹。
            """
            # 绘制主要圆形部分
            pg.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)
    
            # 计算轨迹的透明度,确保其根据对象的生命周期或是否为烟火来变化
            trail_alpha = min(255, self.life * 10) if not self.firework else 255
    
            # 绘制轨迹,每个轨迹点都是一个小圆点,具有计算出的透明度
            for x, y in self.trail_positions:
                pg.draw.circle(win, (self.colour[0], self.colour[1], self.colour[2], trail_alpha), (int(x), int(y)), 1)
    
    

    六、完整代码

    import pygame as pg
    import random as ra
    from collections import deque
    
    pg.init()
    pg.display.set_caption("🎆 Happy New Year! 🎆")
    
    winScreen = pg.display.Info()
    screenWidth = winScreen.current_w
    screenHeight = winScreen.current_h - 66  # Adjust for window title bar
    
    vector = pg.math.Vector2
    
    # 增加颜色多样性
    trail_colors = [
        (255, 0, 0), (255, 165, 0), (255, 255, 0), (0, 255, 0), (0, 0, 255),
        (128, 0, 128), (128, 0, 0), (0, 128, 0), (0, 128, 128), (0, 0, 128)
    ] + [(ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)) for _ in range(50)]
    
    class Firework:
        def __init__(self, initial_y=None):
            """
            初始化一个烟花对象。
    
            本构造函数设置了烟花的颜色、创建了一个粒子对象来表示烟花、设置烟花初始状态为未爆炸、
            并初始化一个双端队列来存储爆炸后产生的粒子。
            """
            # 随机选择一种颜色作为烟花的颜色
            self.colour = trail_colors[ra.randint(0, len(trail_colors)-1)]
    
            # 创建一个粒子对象来表示烟花,初始位置随机,带有指定颜色
            #self.firework = Particle(ra.randint(50, screenWidth), screenHeight, True, [self.colour])
            # 初始化烟花的位置,如果提供了initial_y则使用它,否则使用随机值
            self.firework = Particle(
                ra.randint(50, screenWidth) if initial_y is None else ra.randint(50, screenWidth),  # x坐标随机
                initial_y if initial_y is not None else screenHeight,  # 使用提供的y坐标或随机值
                True,
                [self.colour]
            )
            # 设置烟花初始状态为未爆炸
            self.exploded = False
    
            # 初始化一个双端队列来存储爆炸后产生的粒子
            self.particles = deque()
    
            # 设置粒子数量的最小值和最大值
            self.min_max_particles = vector(100, 300)
    
        def update(self, win):
            """
            更新烟花状态。
    
            如果烟花尚未爆炸,则更新烟花的位置。当烟花需要移除时,表示烟花已爆炸,
            此时生成一系列粒子。如果烟花已经爆炸,则更新所有粒子的状态,并移除需要删除的粒子。
            当所有粒子都被移除后,重置烟花的爆炸状态。
    
            参数:
            win (Window): 游戏窗口对象,用于显示烟花和粒子。
    
            返回:
            无
            """
            if not self.exploded:
                # 更新烟花的位置和状态
                self.firework.update()
                # 当烟花需要移除时,表示烟花已爆炸
                if self.firework.remove:
                    self.exploded = True
                    # 生成随机数量的粒子
                    num_particles = ra.randint(int(self.min_max_particles.x), int(self.min_max_particles.y))
                    # 为每个粒子随机选择颜色
                    particle_colors = [trail_colors[ra.randint(0, len(trail_colors) - 1)] for _ in range(num_particles)]
                    # 创建并添加粒子到粒子列表中
                    for i in range(num_particles):
                        self.particles.append(Particle(self.firework.pos.x, self.firework.pos.y, False, [particle_colors[i]]))
            else:
                # 更新所有粒子的状态
                for p in list(self.particles):
                    p.update()
                    # 移除需要删除的粒子
                    if p.remove:
                        self.particles.remove(p)
                # 当所有粒子都被移除后,重置烟花的爆炸状态
                if not self.particles:
                    self.exploded = False  # Reset exploded state, though typically we wouldn't reset
    
        def draw(self, win):
            """
            绘制烟火和粒子。
    
            如果烟火没有爆炸,则绘制烟火;否则,绘制所有粒子。
    
            参数:
            - win: 绘制烟火和粒子的窗口。
    
            返回值:
            无
            """
            # 检查烟火是否已经爆炸
            if not self.exploded:
                # 如果没有爆炸,绘制烟火
                self.firework.draw(win)
            # 无论烟火是否爆炸,都绘制所有粒子
            for p in self.particles:
                p.draw(win)
    
    class Particle:
        def __init__(self, x, y, firework, colour_list):
            """
            初始化烟火对象的构造函数。
    
            参数:
            x (int): 烟火的初始x坐标。
            y (int): 烟火的初始y坐标。
            firework (bool): 表示是否为烟火。用于区分烟火和粒子的行为。
            colour_list (list): 包含可能的颜色的列表。粒子从中选择一种颜色。
    
            返回:
            None
            """
            self.firework = firework  # 是否为烟火
            self.pos = vector(x, y)  # 当前位置
            self.origin = vector(x, y)  # 初始位置,用于重置或计算轨迹
            self.radius = 60  # 烟火的初始半径或大小
            self.remove = False  # 标记是否应该移除该粒子
            self.life = 0  # 粒子的生命周期计数器
            self.acc = vector(0, 0.05)  # 粒子的加速度,模拟重力效果
            self.size = ra.randint(1, 2)  # 粒子的大小或半径
            self.vel = vector(
                ra.uniform(-2, 2) if not firework else 0,
                -ra.randint(20, 30) if firework else ra.uniform(-2, 2)
            )
            # 根据是否是烟火,设置初始速度。烟火有向上的速度,而粒子在水平方向有速度。
            self.colour = colour_list[0]  # 从传入的颜色列表中选择一个颜色作为粒子的颜色
            # 轨迹的长度,即轨迹中粒子的数量
            self.trail_length = 10
            # 使用deque存储轨迹位置,自动管理最大长度,用于渲染轨迹效果
            self.trail_positions = deque([(x, y)] * self.trail_length, maxlen=self.trail_length)
    
        def update(self):
            """
            更新烟花或粒子的状态。
    
            该方法主要用于更新烟花或粒子的位置,判断其是否需要被移除,以及在其生命周期内追踪其轨迹。
            同时确保粒子不会超出屏幕边界。
            """
            # 更新速度和位置
            self.vel += self.acc
            self.pos += self.vel
    
            # 如果是烟花,判断其是否达到最高点并决定是否移除
            if self.firework:
                if self.pos.y < self.origin.y - 100:
                    self.remove = True
            else:
                # 如果是粒子,增加其生命周期并判断是否达到生命终点
                self.life += 1
                if self.life > 25:
                    self.remove = True
    
                # 确保粒子不会超出屏幕边界
                if self.pos.x < 0:
                    self.pos.x = 0
                elif self.pos.x > screenWidth:
                    self.pos.x = screenWidth-10
                if self.pos.y < 0:
                    self.pos.y = 0
                elif self.pos.y > screenHeight:
                    self.pos.y = screenHeight
    
            # 记录当前位置到轨迹列表,用于后续渲染轨迹
            self.trail_positions.appendleft((self.pos.x, self.pos.y))
    
        def draw(self, win):
            """
            在指定的窗口上绘制当前对象。
    
            参数:
            - win: pygame窗口对象,用于绘制图形。
    
            此方法负责在给定的pygame窗口上绘制当前对象的主要圆形部分和其轨迹。
            """
            # 绘制主要圆形部分
            pg.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)
    
            # 计算轨迹的透明度,确保其根据对象的生命周期或是否为烟火来变化
            trail_alpha = min(255, self.life * 10) if not self.firework else 255
    
            # 绘制轨迹,每个轨迹点都是一个小圆点,具有计算出的透明度
            for x, y in self.trail_positions:
                pg.draw.circle(win, (self.colour[0], self.colour[1], self.colour[2], trail_alpha), (int(x), int(y)), 1)
    
    def main():
        """
        主函数,负责初始化Pygame窗口和时钟,创建烟花对象,并开始主循环以维持程序运行。
        """
        # 初始化Pygame显示窗口
        screen = pg.display.set_mode((screenWidth, screenHeight))
        # 创建Pygame时钟对象,用于控制帧率
        clock = pg.time.Clock()
        # 创建烟花对象列表,初始生成两个烟花
        fireworks = [Firework() for i in range(8)]
        # 设置运行状态为真,用于维持主循环
        running = True
        # 初始化字体对象,用于渲染文本
        font = pg.font.SysFont("SimHei", 120)
        # 定义要显示的文本内容
        text = "财源滚滚"
        # 定义文本颜色
        text_color = (255, 190, 200)
        # 渲染文本
        rendered_text = font.render(text, True, text_color)
        # 计算文本在屏幕上的位置
        text_x = (screenWidth - rendered_text.get_width()) // 2
        text_y = (screenHeight - rendered_text.get_height()) // 2
        # 计算文本高度阈值(文本应该在屏幕中间,所以取屏幕高度的一半减去一些偏移量)
        # 定义文本高度阈值,确保烟花在文本上方且离屏幕顶部有一定距离
        safe_distance_from_top = 100  # 安全距离,可以根据需要调整
        text_height_threshold = max(100, (screenHeight - rendered_text.get_height()) // 2 - safe_distance_from_top)
    
        # 主循环开始
        while running:
            # 控制帧率为60帧/秒
            clock.tick(60)
            # 处理事件,如关闭窗口
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    running = False
            # 填充背景色
            screen.fill((20, 20, 30))
            # 将文本绘制到屏幕上
            screen.blit(rendered_text, (text_x, text_y))
            # 以一定概率生成新的烟花
            # if ra.randint(0, 20) == 1:
            #     fireworks.append(Firework())
            # 以一定概率生成新的烟花,并确保烟花在文本上方绽放
            if ra.randint(0, 20) == 1:
                # 生成一个初始位置在文本上方且离屏幕顶部有一定距离的烟花
                new_firework_y_min = max(100, text_height_threshold - safe_distance_from_top * 2)  # 确保y坐标不会太低
                new_firework_y_max = text_height_threshold - safe_distance_from_top  # 确保y坐标有足够空间给烟花绽放
                new_firework_y = ra.randint(new_firework_y_min, new_firework_y_max)  # 在这个范围内随机选择y坐标
                new_firework = Firework(initial_y=new_firework_y)
                fireworks.append(new_firework)
            # 更新烟花状态,如果烟花爆炸且没有残留粒子,则移除烟花列表
            for fw in fireworks[:]:
                fw.update(screen)
                if fw.exploded and not fw.particles:
                    fireworks.remove(fw)
            # 绘制所有烟花到屏幕上
            for fw in fireworks:
                fw.draw(screen)
            # 更新屏幕显示
            pg.display.flip()
        # 退出Pygame
        pg.quit()
    
    
    if __name__ == "__main__":
        main()
    
  • main 函数: 初始化 Pygame 窗口和时钟,创建烟花对象,并开始主循环。
  • screen: 初始化显示窗口。
  • clock: 创建时钟对象,用于控制帧率。
  • fireworks: 创建烟花对象列表。
  • running: 设置运行状态为真,用于维持主循环。
  • font: 初始化字体对象,用于渲染文本。
  • text: 定义要显示的文本内容。
  • text_color: 定义文本颜色。
  • rendered_text: 渲染文本。
  • text_x 和 text_y: 计算文本在屏幕上的位置。
  • safe_distance_from_top 和 text_height_threshold: 计算文本高度阈值。
  • 主循环:
  • 控制帧率为 60 帧/秒。
  • 处理事件,如关闭窗口。
  • 填充背景色。
  • 将文本绘制到屏幕上。
  • 以一定概率生成新的烟花,并确保烟花在文本上方绽放。
  • 更新烟花状态,如果烟花爆炸且没有残留粒子,则移除烟花列表。
  • 绘制所有烟花到屏幕上。
  • 更新屏幕显示。
  • pg.quit(): 退出 Pygame。
  • 作者:努力努力再努力呐

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【走过路过,不要错过哦】python制作的浪漫烟花,非常烂漫

    发表回复