import pygame
import random
import math
import sys
import os
# 初始化pygame,设置环境变量避免Jupyter中的显示问题
os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"
pygame.init()
# 设置窗口尺寸
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Python烟花特效")
# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
COLORS = [
(255, 0, 0), (0, 255, 0), (0, 0, 255),
(255, 255, 0), (255, 0, 255), (0, 255, 255),
(255, 165, 0), (255, 192, 203), (138, 43, 226)
]
# 烟花粒子类
class Particle:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
self.radius = random.randint(1, 3)
self.speed = random.uniform(2, 6)
self.angle = random.uniform(0, math.pi * 2)
self.vx = math.cos(self.angle) * self.speed
self.vy = math.sin(self.angle) * self.speed
self.gravity = 0.1
self.life = 100
self.alpha = 255
self.trail = []
self.trail_length = 15
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += self.gravity
self.life -= 1
self.alpha = int(self.life * 2.55)
# 添加轨迹点
self.trail.append((int(self.x), int(self.y)))
if len(self.trail) > self.trail_length:
self.trail.pop(0)
def draw(self, surface):
# 绘制轨迹
for i, pos in enumerate(self.trail):
alpha = int(255 * (i / len(self.trail)))
color_with_alpha = (*self.color, alpha)
radius = max(1, int(self.radius * (i / len(self.trail))))
pygame.draw.circle(surface, color_with_alpha, pos, radius)
# 绘制粒子
color_with_alpha = (*self.color, self.alpha)
pygame.draw.circle(surface, color_with_alpha, (int(self.x), int(self.y)), self.radius)
def is_dead(self):
return self.life <= 0 or self.y > HEIGHT or self.x < 0 or self.x > WIDTH
# 烟花类
class Firework:
def __init__(self, x, y):
self.x = x
self.y = y
self.color = random.choice(COLORS)
self.y_velocity = random.uniform(-12, -8)
self.gravity = 0.15
self.particles = []
self.exploded = False
self.target_y = random.randint(50, HEIGHT // 2)
self.speed = random.uniform(2, 4)
self.trail = []
def update(self):
if not self.exploded:
self.y += self.y_velocity
self.y_velocity += self.gravity
# 添加轨迹
self.trail.append((int(self.x), int(self.y)))
if len(self.trail) > 10:
self.trail.pop(0)
# 检查是否需要爆炸
if self.y_velocity >= 0:
self.explode()
else:
# 更新所有粒子
for particle in self.particles[:]:
particle.update()
if particle.is_dead():
self.particles.remove(particle)
def draw(self, surface):
if not self.exploded:
# 绘制轨迹
for i, pos in enumerate(self.trail):
alpha = int(255 * (i / len(self.trail)))
pygame.draw.circle(surface, (*self.color, alpha), pos, max(1, i//3))
# 绘制烟花主体
pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), 4)
pygame.draw.circle(surface, WHITE, (int(self.x), int(self.y)), 2)
else:
# 绘制所有粒子
for particle in self.particles:
particle.draw(surface)
def explode(self):
self.exploded = True
particle_count = random.randint(80, 150) # 正确的变量名
shape = random.choice(["circle", "sphere", "ring", "heart"])
# 修正拼写错误:使用 particle_count 而不是 article_count
for _ in range(particle_count):
if shape == "circle":
self.particles.append(Particle(self.x, self.y, self.color))
elif shape == "sphere":
color = random.choice(COLORS)
self.particles.append(Particle(self.x, self.y, color))
elif shape == "ring":
angle = random.uniform(0, math.pi * 2)
dist = random.uniform(20, 60)
offset_x = math.cos(angle) * dist
offset_y = math.sin(angle) * dist
self.particles.append(Particle(self.x + offset_x, self.y + offset_y, self.color))
elif shape == "heart":
# 心形烟花
t = random.uniform(0, math.pi * 2)
x = 16 * (math.sin(t) ** 3)
y = -(13 * math.cos(t) - 5 * math.cos(2*t) - 2 * math.cos(3*t) - math.cos(4*t))
scale = random.uniform(5, 10)
self.particles.append(Particle(self.x + x * scale, self.y + y * scale, self.color))
def is_dead(self):
return self.exploded and len(self.particles) == 0
# 创建半透明表面用于实现拖尾效果
def create_alpha_surface(width, height):
surface = pygame.Surface((width, height), pygame.SRCALPHA)
surface.fill((0, 0, 0, 25)) # 黑色带透明度
return surface
# 主函数
def main():
# 在Jupyter中需要先初始化显示
from IPython.display import display, clear_output
import ipywidgets as widgets
clock = pygame.time.Clock()
alpha_surface = create_alpha_surface(WIDTH, HEIGHT)
fireworks = []
# 使用系统字体,确保在Jupyter中能正确显示
try:
font = pygame.font.SysFont('Arial', 36)
title_font = pygame.font.SysFont('Arial', 72, bold=True)
except:
font = pygame.font.Font(None, 36)
title_font = pygame.font.Font(None, 72)
# 创建输出小部件
out = widgets.Output()
display(out)
running = True
while running:
with out:
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_SPACE:
# 手动发射烟花
for _ in range(5):
fireworks.append(Firework(random.randint(100, WIDTH-100), HEIGHT))
elif event.type == pygame.MOUSEBUTTONDOWN:
# 点击鼠标发射烟花
fireworks.append(Firework(event.pos[0], HEIGHT))
# 随机发射烟花
if random.random() < 0.05:
fireworks.append(Firework(random.randint(100, WIDTH-100), HEIGHT))
# 应用半透明表面实现拖尾效果
screen.blit(alpha_surface, (0, 0))
# 更新和绘制所有烟花
for firework in fireworks[:]:
firework.update()
firework.draw(screen)
if firework.is_dead():
fireworks.remove(firework)
# 添加地面效果
pygame.draw.rect(screen, (30, 30, 50), (0, HEIGHT - 20, WIDTH, 20))
# 显示标题和说明
title = title_font.render("Python烟花特效", True, (200, 200, 255))
screen.blit(title, (WIDTH//2 - title.get_width()//2, 20))
instructions = [
"按空格键发射烟花",
"点击鼠标发射烟花",
"按ESC键退出"
]
for i, text in enumerate(instructions):
rendered = font.render(text, True, (180, 220, 255))
screen.blit(rendered, (20, 20 + i * 40))
# 显示烟花数量
count_text = font.render(f"烟花数量: {len(fireworks)}", True, (220, 220, 150))
screen.blit(count_text, (WIDTH - count_text.get_width() - 20, 20))
pygame.display.flip()
clock.tick(60)
# 清除之前的输出
clear_output(wait=True)
pygame.quit()
# 在Jupyter中运行
if __name__ == "__main__":
main()
我用jupyter notebook运行的代码,但是出现中文文字显示问题