跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python算法

Python 实现跨年烟花秀

Python 使用 Pygame 库结合粒子系统与物理模拟实现跨年烟花秀效果。代码包含程序初始化、烟花与粒子类设计、痕迹追踪及主循环控制,通过随机数生成颜色与运动轨迹,模拟重力影响下的爆炸扩散。提供完整可运行源码及详细模块解析,解决环境依赖问题,适用于节日特效展示与图形编程学习。

菩提发布于 2026/2/8更新于 2026/9/105.8K 浏览
Python 实现跨年烟花秀

文章配图

写在前面

Python 语言结合 Pygame 库实现新年烟花秀的完整代码。

技术需求

  1. Pygame 库:用于创建图形界面、绘制图形、处理用户输入和管理时间。通过 pg.init() 初始化,pg.display.set_mode() 创建屏幕。
  2. 随机数生成:使用 random 库控制烟花和粒子的颜色、速度、方向等,模拟自然效果。
  3. 物理模拟:利用 Vector2 类表示坐标和速度,模拟重力和粒子运动轨迹。
  4. 粒子系统:烟花爆炸产生多个粒子对象,每个粒子拥有独立属性(颜色、大小、生命周期)。
  5. 路径追踪(Trail):记录粒子位置生成尾迹,模拟轨迹消失效果。
  6. 图形渲染:使用 pg.draw.circle() 和 screen.fill() 绘制粒子与背景。
  7. 动态文本渲染:显示 "Happy New Year!" 文本。
  8. 事件处理:监听窗口关闭事件,控制程序运行状态。
  9. 面向对象编程:封装 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 等待安装完成后再运行程序。

文章配图

文章配图

文章配图

目录

  1. 写在前面
  2. 技术需求
  3. 完整代码
  4. 痕迹类 (Trail)
  5. 粒子类 (Particle)
  6. 烟花类 (Firework)
  7. 更新函数
  8. 主函数 (fire)
  9. 代码分析
  10. 1. 程序初始化与显示设置
  11. 2. 烟花类 (Firework)
  12. 3. 粒子类 (Particle)
  13. 4. 痕迹类 (Trail)
  14. 5. 烟花更新与显示
  15. 6. 主函数 (fire)
  16. 7. 游戏循环
  17. 注意事项

更多推荐文章

查看全部
  • 深入剖析 LangChain:解构大模型的记忆增强策略
  • Revit 模型 Web 展示方案:三步实现 BIM 可视化
  • SRS 流媒体服务器安装配置与使用指南
  • Android 端 Termux 部署 OpenClaw 打造移动端 AI 助理
  • Browser Use 使用指南:AI 自动控制浏览器
  • 无人机 RGB+ 红外双模态小目标行人检测系统构建指南
  • OpenClaw 接入摄像头实战:WSL2 环境下的图像采集方案
  • VSCode 配置 DeepSeek 模型接入 Copilot
  • 宇树 Qmini 双足机器人训练经验总结
  • Playwright 结合 MCP AI 实现自动化浏览器操作
  • 动态规划详解:爬楼梯问题与核心思想
  • Java 后端企业级开发实战:权限控制、缓存优化与并发处理
  • Canon EOS DIGITAL Info - 佳能 EOS DSLR 信息读取与编辑工具
  • NestJS 接口响应 Message 字段编写规范与最佳实践
  • 中小团队低成本搭建项目管理系统:Ubuntu 下 DooTask 私有化部署
  • 鸿蒙 AI App 的技术架构解析
  • Java 对象的序列化和反序列化
  • Springer 期刊 Signal, Image and Video Processing 投稿指南与常见问题
  • Xilinx Clocking Wizard IP 核完全指南:从基础到高级应用
  • 拆解机器人底盘 DDSM400 钕强磁外转子 65mm 伺服轮毂电机

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online