当前位置: 首页 > article >正文

使用Pygame制作“动态烟花”

1. 前言

在一些简单的图形工具(例如 turtle)里,我们可以用静态绘制来模拟“烟花”形状,但这往往缺少逼真的运动轨迹爆炸粒子的效果。本篇文章将使用 Pygame 这个 2D 游戏开发框架来实现烟花从地面升空到空中散落的一套简易动画,丰富你的编程体验,也为大家的节日增添一点氛围。

Pygame 介绍
Pygame 是用 Python 编写的 2D 游戏和多媒体程序开发库。它基于 SDL 库,可以让开发者轻松地管理窗口、图形、声音、事件(例如键盘或鼠标输入)等,实现一些基础的游戏或动画。

2. 开发环境准备

  1. Python 版本:Python 3.x
  2. Pygame:可通过 pip install pygame 安装。
  3. 系统:本示例在 Windows 和大部分 Linux 系统上都可运行,macOS 也支持。但需要保证你有一个可显示图形界面的环境。

安装好 Pygame 后,即可开始我们的烟花之旅!


3. 实现思路

要实现一个简单的“烟花”动画,我们可以使用粒子系统(Particle System)的思想进行设计。主要流程如下:

  1. 发射阶段(Rocket)

    • 烟花最初是一枚从地面发射的火箭。我们给它一个初始位置(地面)、向上的速度、颜色等属性。
    • 随着时间推移,火箭不断上升,速度可能会受到重力或空气阻力的影响(可根据需求简化或增加物理效果)。
  2. 爆炸阶段(Explosion)

    • 当火箭到达一定高度或满足某些随机条件后,火箭会“爆炸”成许多粒子。
    • 这些粒子会向四面八方飞散,并且在运动过程中慢慢减速下落,最终消失。
  3. 循环绘制

    • 在游戏循环里,每帧都需要更新火箭/粒子的状态(位置、速度、寿命)并绘制它们。
    • 当一束烟花完全消失后,可以根据设定随机产生新的烟花,实现持续的烟花表演。

接下来,我们会定义两个类:

  • Particle:代表单个粒子(包括爆炸后的小火花,也可以代表火箭本身)。
  • Firework:代表一朵烟花,其内部有一个“火箭粒子”,在爆炸后会生成多个“爆炸粒子”。

4. 核心代码

下面是一个简化的示例。你可以把它保存成一个 .py 文件,然后运行观察效果。

提示:由于烟花的随机性,每次运行效果会略有不同;你也可以自由修改代码中的各项参数(速度、颜色、加速度、粒子数量等),打造自己独特的烟花效果!

import pygame
import random
import math

# 屏幕大小
WIDTH, HEIGHT = 800, 600

# 颜色定义(RGB)
BLACK = (0, 0, 0)

# 初始化 pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("新年烟花 - Pygame 动画示例")
clock = pygame.time.Clock()

class Particle:
    """
    粒子类:可用于表示烟花火箭或爆炸后的火花
    """
    def __init__(self, x, y, vx, vy, color, lifespan=80):
        self.x = x               # 粒子位置 x
        self.y = y               # 粒子位置 y
        self.vx = vx             # 水平速度
        self.vy = vy             # 垂直速度
        self.color = color       # 粒子颜色
        self.lifespan = lifespan # 粒子生命周期
        self.alive = True        # 是否存活

    def update(self):
        # 更新粒子状态:位置 + 重力 + 寿命衰减
        self.x += self.vx
        self.y += self.vy
        # 简易重力模拟
        self.vy += 0.1

        self.lifespan -= 1
        if self.lifespan <= 0:
            self.alive = False

    def draw(self, surface):
        # 根据寿命来控制透明度(可选)
        # 让粒子在即将消失时逐渐变淡
        alpha = max(0, int(255 * (self.lifespan / 80)))
        color_with_alpha = (*self.color, alpha)

        # 在 Pygame 中可用 Surface.set_alpha 或者直接 draw circle
        # 这里简单处理:画一个小圆点
        pygame.draw.circle(surface, color_with_alpha[:3],
                           (int(self.x), int(self.y)), 3)

class Firework:
    """
    烟花类:先有一个火箭,一定时间后爆炸成一堆粒子。
    """
    def __init__(self):
        # 随机初始位置(地面附近)
        self.x = random.randint(100, WIDTH - 100)
        self.y = HEIGHT
        # 向上发射的速度
        self.vx = random.uniform(-1, 1)
        self.vy = random.uniform(-6, -8)
        # 随机生成一种颜色 (较亮)
        self.color = (random.randint(128, 255),
                      random.randint(128, 255),
                      random.randint(128, 255))
        # 初始就有一个火箭粒子
        self.rocket = Particle(self.x, self.y, self.vx, self.vy, self.color, lifespan=60)
        self.exploded = False
        self.particles = []

    def update(self):
        if not self.exploded:
            # 如果火箭还没爆炸,则更新火箭位置
            self.rocket.update()
            # 判断是否满足爆炸条件
            # 1) 火箭速度向下(vy > 0)表明到达顶点
            # 2) 或者火箭寿命到头
            if self.rocket.vy > 0 or self.rocket.lifespan < 20:
                self.explode()
        else:
            # 如果已经爆炸,就更新所有爆炸粒子
            for p in self.particles:
                p.update()

        # 清理已死亡的粒子,防止列表无限增长
        self.particles = [p for p in self.particles if p.alive]

    def explode(self):
        """ 火箭爆炸时,生成一群粒子。 """
        self.exploded = True
        # 在爆炸位置生成若干粒子
        num_particles = random.randint(20, 40)
        for _ in range(num_particles):
            # 随机方向和速度
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(2, 5)
            vx = speed * math.cos(angle)
            vy = speed * math.sin(angle) - 2  # 适当给点向上的初速度
            # 粒子使用与火箭相同的颜色,或你也可以随机色
            p = Particle(self.rocket.x, self.rocket.y, vx, vy, self.color,
                         lifespan=random.randint(50, 80))
            self.particles.append(p)

    def draw(self, surface):
        # 如果火箭还在且没爆炸,画火箭
        if not self.exploded and self.rocket.alive:
            self.rocket.draw(surface)
        else:
            # 画爆炸后的粒子
            for p in self.particles:
                p.draw(surface)

    @property
    def is_alive(self):
        # 烟花是否还存在?只有当火箭和所有粒子都死亡时才算结束
        if not self.exploded:
            return self.rocket.alive
        else:
            return any(p.alive for p in self.particles)

def main():
    fireworks = []
    running = True
    while running:
        clock.tick(30)  # 控制帧率
        screen.fill(BLACK)

        # 1) 处理退出事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        
        # 2) 随机产生新的烟花
        if random.random() < 0.03:  # 3% 概率每帧生成一枚新的烟花
            fireworks.append(Firework())

        # 3) 更新并绘制所有烟花
        for fw in fireworks:
            fw.update()
            fw.draw(screen)

        # 4) 清理已经完全结束的烟花
        fireworks = [fw for fw in fireworks if fw.is_alive]

        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()

代码说明

  1. Particle 粒子类

    • x, y:粒子的当前位置。
    • vx, vy:粒子的速度,vy 会在每帧被加上一定的重力。
    • lifespan:粒子存活时间,每帧递减,到 0 则 alive = False
    • update():更新粒子状态,包含位移、重力、寿命衰减。
    • draw():在屏幕上以小圆点的形式绘制自己,使用 pygame.draw.circle()
  2. Firework 烟花类

    • 包含一个“火箭”粒子(在 exploded=False 时代表飞向空中的火箭),和一组“爆炸粒子”列表。
    • update()
      • 若未爆炸,则更新火箭位置,判断爆炸条件(例如火箭已到最高点或寿命耗尽),然后进入爆炸函数。
      • 若已爆炸,则更新所有爆炸粒子的位置、速度等。
    • explode():生成一定数量的粒子来模拟四散的火花,给它们随机的速度与寿命。
    • draw():区分是否已经爆炸,决定画火箭还是画分散的粒子。
    • is_alive:只要火箭或爆炸粒子还在活动,就算烟花存活。
  3. 主循环 (main())

    • fireworks 列表里存放现有的烟花对象。
    • if random.random() < 0.03::每帧有 3% 的概率产生一个新的烟花,从而在整个动画过程中,烟花会不断随机出现。
    • 每一帧都要先 更新 所有烟花 (fw.update()),再 绘制 (fw.draw(screen))。
    • pygame.display.flip() 将绘制内容显示到窗口上。
    • 用一个列表推导式 fireworks = [fw for fw in fireworks if fw.is_alive] 清理已经彻底消失的烟花。
    • 通过 clock.tick(30) 将动画限制在 30 帧左右,流畅且不会占用太高 CPU。

5. 运行与效果

  1. 运行
    • 将以上代码保存为 fireworks.py,然后在命令行执行 python fireworks.py(或双击运行)。
  2. 效果
    • 程序启动后,会在 800×600 的窗口中随机产生烟花。每次烟花先从地面发射、上升到一定高度后爆炸,并生成彩色粒子四散而下。随后又会随机出现新的烟花,循环往复,直到你关闭窗口。

在这里插入图片描述

如果你想更“热闹”一些,可以将 if random.random() < 0.03: 改大,比如 0.1,则产生烟花的频率会显著增加。


6. 参数调优与扩展

  1. 调整粒子数、速度和寿命
    • Firework.explode() 中的 num_particles 可以让烟花更密集或稀疏;
    • (vx, vy) 的范围和 lifespan 会影响火花飞溅范围和消散速度。
  2. 添加随机颜色
    • 目前的设计是火箭与爆炸粒子使用同色,可以改为每个粒子都生成一个随机色,让烟花更加绚丽。
  3. 增添交互
    • 可以让玩家按空格或鼠标点击来触发一朵烟花,增加游戏化的体验。
  4. 添加更多物理效果
    • 阻力、风力、空气阻力等等,能使烟花运动路径更真实。
  5. 背景音乐或音效
    • Pygame 可以加载并播放音效,为烟花添加绽放的“砰”声,为你的新年更添气氛。

7. 总结

使用 Pygame 实现的烟花动画,能更直观地体验到火箭发射、空中爆炸和粒子下落的过程。通过粒子系统的思想,我们可以在游戏或动画中模拟诸如火花、尘埃、雨雪、爆炸等特效。在以上示例的基础上,你还可以扩展更多的特效和细节,打造一场绚丽多彩的新年烟花秀。

如果你对更复杂的 2D/3D 动画或游戏开发感兴趣,Pygame 也是一个很好的起点。相信随着你对粒子系统和游戏循环原理的不断理解,你能在趣味编程的道路上更进一步。

最后,祝大家新年快乐、编程顺利、烟花绚烂!


http://www.kler.cn/a/527636.html

相关文章:

  • 栈和队列特别篇:栈和队列的经典算法问题
  • pytorch基于FastText实现词嵌入
  • Fiddler(一) - Fiddler简介_fiddler软件
  • OpenCV 版本不兼容导致的问题
  • PyTorch 快速入门
  • XCTF - IllIntentions wp
  • 基于互联网+智慧水务信息化整体解决方案
  • unity学习25:用 transform 进行旋转和移动,简单的太阳地球月亮模型,以及父子级关系
  • 【Pandas】pandas Series diff
  • C语言指针专题二 -- 字符指针与字符串
  • 翻译: Anthropic CEO:DeepSeek-R1是人工智能领域的革命吗?二
  • 一文读懂fgc之cms
  • web安全测试之 xss攻击_request
  • [openwrt] odhcpd ra_management Vs ra_flags 和 ra_slaac
  • 守护进程
  • 代码随想录34 动态规划
  • C动态库的生成与在Python和QT中的调用方法
  • 猿人学web 19题(js逆向)
  • 为AI聊天工具添加一个知识系统 之70 详细设计 之11 维度运动控制的应用:上下文受控的自然语言
  • Git进阶之旅:Git 分支管理
  • gcc和g++的区别以及明明函数有定义为何链接找不到
  • 计算机网络——流量控制
  • CSS 溢出内容处理:从基础到实战
  • 解锁豆瓣高清海报(一) 深度爬虫与requests进阶之路
  • [EAI-029] RoboVLMs,基于VLM构建VLA模型的消融研究
  • Ubuntu 系统,如何使用双Titan V跑AI