ARTICLE · 1066605
节日源码:pygame国庆版5种类型烟花
节日源码:pygame国庆版5种类型烟花

绘制时用 life/max_life 同时控制亮度和大小,比 alpha 快。 五种花型 牡丹:角度+速度都随机 → 均匀圆 环形:角度均匀 + Y轴压扁 柳树:只改物理(重力大、阻力大) 心形:参数方程直接当速度,Y 取负 菊花:内外两层,不同速度+颜色 保护:粒子超 2600 个就删最老的。 


Python,速成心法
敲代码,查资料,问度娘
练习,探索,总结,优化

★★★★★博文创作不易,使用代码的过程中,如有疑问的地方,欢迎大家指正留言交流。喜欢的老铁可以多多点赞+收藏分享+置顶,小红牛在此表示感谢。★★★★★
-------★Pygame经典游戏★-------
pygame 版国庆烟花:带粒子系统、拖尾残影、5 种花型(牡丹/环形/柳树/心形/菊花),空格手动发射,鼠标点击就地炸开。
三个核心
Particle | |
Rocket | explode() |
explode() |
拖尾残影(视觉关键)
fade.set_alpha(24) # 每帧盖一层半透明黑screen.blit(fade, (0,0))
不是清屏,是让旧画面慢慢变暗。数字越小拖尾越长。
粒子物理
k = dt * 60 # 归一化帧率vx *= drag # 阻力vy += gravity * k # 重力life -= k # 寿命

↓ 源码如下 ↓
# -*- coding: utf-8 -*-# @Author : 小红牛# 微信公众号:wdPythonimport pygameimport mathimport randomimport syspygame.init()W, H = 900, 620screen = pygame.display.set_mode((W, H))pygame.display.set_caption("国庆烟花 · pygame")clock = pygame.time.Clock()TAU = math.tau# 半透明黑层,每帧盖一次形成拖尾残影fade = pygame.Surface((W, H))fade.fill((0, 0, 0))fade.set_alpha(24)def get_font(size, bold=False):for name in ("microsoftyahei", "simhei", "pingfangsc", "hiraginosansgb","notosanscjksc", "wenquanyimicrohei", "arialunicodems"):path = pygame.font.match_font(name, bold=bold)if path:return pygame.font.Font(path, size)return pygame.font.SysFont(None, size)FONT_BIG = get_font(52, bold=True)FONT_SMALL = get_font(18)PALETTE = [(255, 82, 82), (255, 168, 60), (255, 232, 90), (120, 255, 140),(90, 210, 255), (170, 140, 255), (255, 130, 200), (255, 255, 255),]class Particle:__slots__ = ("x", "y", "vx", "vy", "color", "life", "max_life","radius", "gravity", "drag")def __init__(self, x, y, vx, vy, color, life, radius,gravity=0.055, drag=0.985):self.x, self.y = x, yself.vx, self.vy = vx, vyself.color = colorself.life = self.max_life = lifeself.radius = radiusself.gravity = gravityself.drag = dragdef update(self, dt):k = dt * 60self.vx *= self.dragself.vy *= self.dragself.vy += self.gravity * kself.x += self.vx * kself.y += self.vy * kself.life -= kdef draw(self, surf):f = self.life / self.max_lifeif f <= 0:returnr = max(1, int(self.radius * (0.35 + 0.65 * f)))col = (int(self.color[0] * f), int(self.color[1] * f), int(self.color[2] * f))pygame.draw.circle(surf, col, (int(self.x), int(self.y)), r)def explode(x, y, color, kind):"""按花型生成一批粒子"""out = []if kind == "peony": # 牡丹:均匀球形for _ in range(random.randint(90, 130)):a = random.uniform(0, TAU)sp = random.uniform(0.5, 6.2)out.append(Particle(x, y, math.cos(a) * sp, math.sin(a) * sp,color, random.uniform(55, 95), 2.2))elif kind == "ring": # 环形:带倾斜的圆环n = 90tilt = random.uniform(0.35, 0.75)for i in range(n):a = TAU * i / nsp = 5.4 + random.uniform(-0.25, 0.25)out.append(Particle(x, y, math.cos(a) * sp, math.sin(a) * sp * tilt,color, random.uniform(60, 85), 2.0))elif kind == "willow": # 柳树:重力大、下坠慢for _ in range(random.randint(70, 95)):a = random.uniform(0, TAU)sp = random.uniform(0.6, 4.6)out.append(Particle(x, y, math.cos(a) * sp, math.sin(a) * sp,color, random.uniform(90, 150), 2.4,gravity=0.14, drag=0.972))elif kind == "heart": # 心形:参数方程采样n = 110for i in range(n):t = TAU * i / npx = 16 * math.sin(t) ** 3py = (13 * math.cos(t) - 5 * math.cos(2 * t)- 2 * math.cos(3 * t) - math.cos(4 * t))k = 0.36out.append(Particle(x, y, px * k, -py * k, color,random.uniform(70, 100), 2.2))else: # 菊花:双层双色c2 = random.choice(PALETTE)for layer, (n, sp0, sp1) in enumerate(((70, 2.0, 3.2), (60, 4.4, 6.0))):col = color if layer == 0 else c2for _ in range(n):a = random.uniform(0, TAU)sp = random.uniform(sp0, sp1)out.append(Particle(x, y, math.cos(a) * sp, math.sin(a) * sp,col, random.uniform(65, 100), 2.1))return outKINDS = ["peony", "peony", "ring", "willow", "heart", "chrysanthemum"]class Rocket:"""升空的火箭,到高度后炸开"""def __init__(self, x=None, target_y=None, color=None, kind=None):self.x = x if x is not None else random.uniform(120, W - 120)self.y = float(H + 10)self.target_y = target_y if target_y is not None else random.uniform(70, H * 0.45)self.color = color or random.choice(PALETTE)self.kind = kind or random.choice(KINDS)self.vy = -random.uniform(9.5, 12.5)self.vx = random.uniform(-0.8, 0.8)def update(self, dt):k = dt * 60self.x += self.vx * kself.y += self.vy * kself.vy += 0.045 * kreturn self.vy >= -0.5 or self.y <= self.target_ydef draw(self, surf):for i in range(1, 6):a = 1 - i / 6r = max(1, int(3 * a))col = (int(255 * a), int(180 * a), int(60 * a))pygame.draw.circle(surf, col,(int(self.x - self.vx * i * 0.6), int(self.y - self.vy * i * 0.6)), r)pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), 3)pygame.draw.circle(surf, (255, 255, 255), (int(self.x), int(self.y)), 1)def main():particles, rockets = [], []spawn_timer, next_spawn = 0.0, 0.35running = Truewhile running:dt = min(clock.tick(60) / 1000.0, 0.05)for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_ESCAPE:running = Falseelif event.key == pygame.K_SPACE:rockets.append(Rocket())elif event.type == pygame.MOUSEBUTTONDOWN:mx, my = event.posparticles.extend(explode(mx, my, random.choice(PALETTE),random.choice(KINDS)))# 拖尾:整屏轻微变暗screen.blit(fade, (0, 0))# 自动发射spawn_timer += dtif spawn_timer >= next_spawn:spawn_timer = 0.0next_spawn = random.uniform(0.35, 0.95)rockets.append(Rocket())# 火箭for rk in rockets[:]:if rk.update(dt):particles.extend(explode(rk.x, rk.y, rk.color, rk.kind))rockets.remove(rk)else:rk.draw(screen)# 粒子for p in particles[:]:p.update(dt)if p.life <= 0 or p.x < -80 or p.x > W + 80 or p.y > H + 80:particles.remove(p)else:p.draw(screen)if len(particles) > 2600: # 防止堆积del particles[:len(particles) - 2600]# 文字t = FONT_BIG.render("国 庆 快 乐", True, (255, 215, 90))screen.blit(t, (W // 2 - t.get_width() // 2, H - 108))s = FONT_SMALL.render("空格:发射 鼠标点击:就地炸开 ESC:退出",True, (210, 215, 235))screen.blit(s, (W // 2 - s.get_width() // 2, H - 44))pygame.display.flip()pygame.quit()sys.exit()if __name__ == "__main__":main()
完毕!!感谢您的收看
--------★★历史博文集合★★--------