import pygame
import random
import math
import sys

# 初始化Pygame
pygame.init()

# 屏幕设置
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = (10, 10, 30)  # 深蓝色夜空

# 粒子物理参数
GRAVITY = 0.5
FRICTION = 0.98

# 颜色定义（RGB）
COLORS = [
    (255, 50, 50),   # 红
    (255, 200, 50),  # 橙黄
    (255, 255, 50),  # 黄
    (50, 255, 50),   # 绿
    (50, 200, 255),  # 天蓝
    (255, 50, 150),  # 粉红
    (180, 50, 255),  # 紫
    (255, 140, 50),  # 橙
]

class Particle:
    """烟花粒子类，用于升空粒子和爆炸粒子"""
    def __init__(self, x, y, vx, vy, color, size, lifetime, is_trail=False):
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy
        self.color = color
        self.size = size
        self.lifetime = lifetime  # 剩余生命帧数
        self.max_lifetime = lifetime
        self.is_trail = is_trail  # 是否为升空轨迹粒子
        
    def update(self):
        """更新粒子位置和速度"""
        self.vx *= FRICTION
        self.vy += GRAVITY
        self.x += self.vx
        self.y += self.vy
        self.lifetime -= 1
        
    def draw(self, screen):
        """绘制粒子（根据生命周期渐变透明度/大小）"""
        alpha = self.lifetime / self.max_lifetime
        # 根据生命周期调整大小和亮度
        current_size = max(1, int(self.size * alpha))
        if current_size <= 0:
            return
            
        # 计算渐变颜色（向黑色/暗色过渡）
        color = tuple(int(c * alpha) for c in self.color)
        
        # 绘制圆形粒子
        pygame.draw.circle(screen, color, (int(self.x), int(self.y)), current_size)
        
    def is_alive(self):
        return self.lifetime > 0


class Firework:
    """烟花类，管理升空和爆炸过程"""
    def __init__(self, x, target_y, color=None):
        self.x = x
        self.y = SCREEN_HEIGHT  # 从底部开始
        self.target_y = target_y
        self.color = color if color else random.choice(COLORS)
        self.particles = []  # 存储爆炸后的粒子
        self.trail_particles = []  # 存储升空轨迹粒子
        self.state = "rising"  # rising 或 exploding
        self.speed = random.uniform(-8, -12)  # 上升速度（负值向上）
        self.exploded = False
        
    def update(self):
        if self.state == "rising":
            # 更新位置
            self.y += self.speed
            
            # 添加轨迹粒子
            if random.random() < 0.3:
                trail = Particle(
                    self.x, self.y,
                    random.uniform(-1, 1), random.uniform(-1, 1),
                    self.color, 2, 15, is_trail=True
                )
                self.trail_particles.append(trail)
            
            # 更新现有轨迹粒子
            self.trail_particles = [p for p in self.trail_particles if p.is_alive()]
            for p in self.trail_particles:
                p.update()
            
            # 到达目标高度或超出屏幕顶部时爆炸
            if self.y <= self.target_y or self.y < 50:
                self.explode()
                
        elif self.state == "exploding":
            # 更新爆炸粒子
            self.particles = [p for p in self.particles if p.is_alive()]
            for p in self.particles:
                p.update()
                
            # 更新残留轨迹粒子
            self.trail_particles = [p for p in self.trail_particles if p.is_alive()]
            for p in self.trail_particles:
                p.update()
                
    def explode(self):
        """产生爆炸粒子效果"""
        self.state = "exploding"
        num_particles = random.randint(60, 120)
        
        for _ in range(num_particles):
            # 随机速度方向（圆形扩散）
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(3, 8)
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed
            
            # 随机大小和生命
            size = random.randint(2, 4)
            lifetime = random.randint(40, 80)
            
            # 颜色轻微随机变化
            color_variation = random.randint(-40, 40)
            particle_color = (
                max(0, min(255, self.color[0] + color_variation)),
                max(0, min(255, self.color[1] + color_variation)),
                max(0, min(255, self.color[2] + color_variation))
            )
            
            particle = Particle(self.x, self.y, vx, vy, particle_color, size, lifetime)
            self.particles.append(particle)
            
        # 添加一些火星效果（更小更快的粒子）
        for _ in range(30):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(5, 12)
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed
            spark = Particle(self.x, self.y, vx, vy, (255, 200, 100), 1, 20)
            self.particles.append(spark)
            
    def draw(self, screen):
        """绘制烟花及其所有粒子"""
        if self.state == "rising":
            # 绘制升空弹头
            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), 4)
            # 绘制轨迹
            for p in self.trail_particles:
                p.draw(screen)
        else:
            # 绘制爆炸粒子
            for p in self.particles:
                p.draw(screen)
            # 绘制残留轨迹
            for p in self.trail_particles:
                p.draw(screen)
                
    def is_finished(self):
        """检查烟花是否完全消失"""
        if self.state == "exploding":
            return len(self.particles) == 0 and len(self.trail_particles) == 0
        return False


class FireworkSystem:
    """烟花系统，管理多个烟花的生成和更新"""
    def __init__(self, screen):
        self.screen = screen
        self.fireworks = []
        self.next_firework_time = 0
        
    def update(self, current_time):
        """更新所有烟花并生成新烟花"""
        # 更新现有烟花
        for firework in self.fireworks[:]:
            firework.update()
            if firework.is_finished():
                self.fireworks.remove(firework)
                
        # 随机生成新烟花（每0.5-2秒生成一个）
        if current_time >= self.next_firework_time and len(self.fireworks) < 8:
            self.next_firework_time = current_time + random.uniform(0.5, 1.5)
            # 随机生成位置和颜色
            x = random.randint(50, SCREEN_WIDTH - 50)
            target_y = random.randint(80, SCREEN_HEIGHT // 2)
            color = random.choice(COLORS)
            self.fireworks.append(Firework(x, target_y, color))
            
    def draw(self):
        """绘制所有烟花"""
        for firework in self.fireworks:
            firework.draw(self.screen)
            
    def add_firework_at_mouse(self, x, y):
        """在鼠标位置添加一个烟花（用于交互）"""
        color = random.choice(COLORS)
        self.fireworks.append(Firework(x, y, color))


def main():
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("动态烟花效果 - Pygame")
    clock = pygame.time.Clock()
    
    firework_system = FireworkSystem(screen)
    
    # 初始生成几个烟花
    for _ in range(3):
        x = random.randint(100, SCREEN_WIDTH - 100)
        target_y = random.randint(100, SCREEN_HEIGHT // 2)
        color = random.choice(COLORS)
        firework_system.fireworks.append(Firework(x, target_y, color))
    
    running = True
    # 用于记录鼠标点击的变量
    mouse_down = False
    mouse_pos = (0, 0)
    
    while running:
        current_time = pygame.time.get_ticks() / 1000.0  # 秒为单位
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:  # 左键点击
                    mouse_down = True
                    mouse_pos = pygame.mouse.get_pos()
            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    mouse_down = False
        
        # 鼠标按下时持续生成烟花（拖拽效果）
        if mouse_down:
            # 限制生成频率，避免过多
            if random.random() < 0.1:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                # 让烟花从鼠标位置升起并爆炸（目标高度比鼠标略高）
                target_y = max(50, mouse_y - 30)
                color = random.choice(COLORS)
                firework_system.fireworks.append(Firework(mouse_x, target_y, color))
        
        # 更新系统
        firework_system.update(current_time)
        
        # 绘制
        screen.fill(BACKGROUND_COLOR)
        firework_system.draw()
        
        # 显示提示文字
        font = pygame.font.SysFont("simhei", 18)
        tip_text = font.render("点击或拖拽鼠标来添加烟花 | ESC退出", True, (200, 200, 200))
        screen.blit(tip_text, (10, SCREEN_HEIGHT - 30))
        
        pygame.display.flip()
        clock.tick(60)  # 60帧每秒
        
    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()