【走过路过,不要错过哦】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。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值