import pygame
import random
import sys

# --- 初始化 ---
pygame.init()
pygame.font.init()

# --- 常量定义 ---
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 60

# 颜色定义
COLOR_BG = (135, 206, 235)      # 天空蓝
COLOR_PLAYER = (255, 255, 0)    # 黄色飞机
COLOR_OBSTACLE = (34, 139, 34)  # 绿色柱子
COLOR_OBSTACLE_BORDER = (0, 100, 0)  # 深绿边框
COLOR_TEXT = (255, 255, 255)
COLOR_PARTICLE = (255, 255, 255)  # 白色粒子

# 物理参数
GRAVITY = 0.25
LIFT = -6  # 向上飞的力度
OBSTACLE_GAP = 180  # 障碍物中间的缝隙大小
OBSTACLE_SPEED = 4
OBSTACLE_FREQUENCY = 1500  # 毫秒，生成障碍物的间隔


class Particle:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.vx = random.uniform(-2, 2)
        self.vy = random.uniform(-2, 2)
        self.life = 30
        self.size = random.randint(2, 5)

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.life -= 1
        self.size *= 0.95
        return self.life > 0

    def draw(self, surface):
        if self.size < 1:
            return
        pygame.draw.circle(surface, COLOR_PARTICLE,
                           (int(self.x), int(self.y)), int(self.size))


class Player:
    def __init__(self):
        self.x = 100
        self.y = SCREEN_HEIGHT // 2
        self.width = 40
        self.height = 30
        self.vel_y = 0
        self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
        self.alive = True
        self.particles = []

    def flap(self):
        self.vel_y = LIFT
        # 喷射粒子
        for _ in range(5):
            self.particles.append(Particle(self.rect.left, self.rect.centery))

    def update(self):
        if not self.alive:
            return

        # 应用重力
        self.vel_y += GRAVITY
        self.y += self.vel_y

        # 边界限制
        if self.y > SCREEN_HEIGHT - self.height:
            self.y = SCREEN_HEIGHT - self.height
            self.vel_y = 0
            self.die()
        elif self.y < 0:
            self.y = 0
            self.vel_y = 0

        self.rect.y = int(self.y)

        # 更新粒子
        self.particles = [p for p in self.particles if p.update()]

    def die(self):
        self.alive = False
        # 死亡爆炸
        for _ in range(30):
            self.particles.append(
                Particle(self.rect.centerx, self.rect.centery))

    def draw(self, surface):
        # 绘制粒子
        for p in self.particles:
            p.draw(surface)

        if not self.alive:
            return

        # 绘制飞机 (简单的三角形)
        points = [
            (self.rect.left, self.rect.centery),  # 机头
            (self.rect.right, self.rect.top),    # 右上
            (self.rect.right, self.rect.bottom)  # 右下
        ]
        pygame.draw.polygon(surface, COLOR_PLAYER, points)
        # 驾驶舱
        pygame.draw.circle(surface, (0, 0, 0),
                           (self.rect.left + 15, self.rect.centery - 5), 5)


class Obstacle:
    def __init__(self, x, speed):
        self.x = x
        self.width = 60
        self.speed = speed
        # 随机生成缝隙的位置
        # 保证缝隙上下至少留出 50px 的柱子
        min_gap_y = 100
        max_gap_y = SCREEN_HEIGHT - 100 - OBSTACLE_GAP
        self.gap_y = random.randint(min_gap_y, max_gap_y)

        # 上柱子
        self.top_rect = pygame.Rect(self.x, 0, self.width, self.gap_y)
        # 下柱子
        self.bottom_rect = pygame.Rect(
            self.x, self.gap_y + OBSTACLE_GAP, self.width, SCREEN_HEIGHT - (self.gap_y + OBSTACLE_GAP))

        self.passed = False  # 标记是否已经通过，用于计分

    def update(self):
        self.x -= self.speed
        self.top_rect.x = self.x
        self.bottom_rect.x = self.x

    def draw(self, surface):
        # 绘制柱子
        pygame.draw.rect(surface, COLOR_OBSTACLE, self.top_rect)
        pygame.draw.rect(surface, COLOR_OBSTACLE, self.bottom_rect)
        # 绘制边框增加立体感
        pygame.draw.rect(surface, COLOR_OBSTACLE_BORDER, self.top_rect, 3)
        pygame.draw.rect(surface, COLOR_OBSTACLE_BORDER, self.bottom_rect, 3)


def draw_text(surface, text, size, x, y, color=COLOR_TEXT, center=True):
    font = pygame.font.Font(None,size)
    render = font.render(text, True, color)
    rect = render.get_rect()
    if center:
        rect.center = (x, y)
    else:
        rect.topleft = (x, y)
    surface.blit(render, rect)


def main():
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("Python 飞行躲避")
    clock = pygame.time.Clock()

    player = Player()
    obstacles = []

    score = 0
    high_score = 0

    # 计时器用于生成障碍物
    obstacle_timer = pygame.USEREVENT + 1
    pygame.time.set_timer(obstacle_timer, OBSTACLE_FREQUENCY)

    state = "START"  # START, PLAYING, GAMEOVER

    running = True
    while running:
        # 1. 事件处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    if state == "START":
                        state = "PLAYING"
                        player = Player()
                        obstacles = []
                        score = 0
                        # 重置定时器
                        pygame.time.set_timer(
                            obstacle_timer, OBSTACLE_FREQUENCY)
                    elif state == "PLAYING":
                        player.flap()
                    elif state == "GAMEOVER":
                        state = "START"

            if event.type == pygame.MOUSEBUTTONDOWN:
                if state == "PLAYING":
                    player.flap()

            if event.type == obstacle_timer and state == "PLAYING":
                # 生成障碍物
                # 随着分数增加，速度略微加快
                current_speed = OBSTACLE_SPEED + (score // 10) * 0.5
                obstacles.append(Obstacle(SCREEN_WIDTH, current_speed))

                # 随着分数增加，生成频率加快
                current_freq = max(800, OBSTACLE_FREQUENCY - (score // 5) * 50)
                pygame.time.set_timer(obstacle_timer, int(current_freq))

        # 2. 逻辑更新
        if state == "PLAYING":
            player.update()

            # 更新障碍物
            for obs in obstacles[:]:
                obs.update()

                # 移除超出屏幕的障碍物
                if obs.x + obs.width < 0:
                    if obs in obstacles:
                        obstacles.remove(obs)

                # 碰撞检测
                if player.alive:
                    if (player.rect.colliderect(obs.top_rect) or
                            player.rect.colliderect(obs.bottom_rect)):
                        player.die()
                        state = "GAMEOVER"
                        if score > high_score:
                            high_score = score

                # 计分
                if not obs.passed and player.rect.left > obs.x + obs.width:
                    score += 1
                    obs.passed = True

        # 3. 绘制渲染
        screen.fill(COLOR_BG)

        # 绘制云层装饰 (简单的圆圈)
        pygame.draw.circle(screen, (255, 255, 255), (100, 100), 40)
        pygame.draw.circle(screen, (255, 255, 255), (140, 110), 50)
        pygame.draw.circle(screen, (255, 255, 255), (600, 400), 60)

        # 绘制实体
        if state != "START":
            for obs in obstacles:
                obs.draw(screen)
            player.draw(screen)

        # UI 显示
        draw_text(screen, f"Score: {score}", 40, SCREEN_WIDTH // 2, 40)
        draw_text(screen, f"High Score: {high_score}",
                  20, SCREEN_WIDTH - 100, 40, center=False)

        if state == "START":
            draw_text(screen, "飞行躲避", 60, SCREEN_WIDTH //
                      2, SCREEN_HEIGHT//2 - 50)
            draw_text(screen, "按 [空格] 或 [鼠标左键] 起飞", 30,
                      SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 20)
            draw_text(screen, "躲避绿色柱子", 20, SCREEN_WIDTH //
                      2, SCREEN_HEIGHT - 40, (50, 50, 50))

        elif state == "GAMEOVER":
            # 半透明遮罩
            s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
            s.set_alpha(150)
            s.fill((0, 0, 0))
            screen.blit(s, (0, 0))

            draw_text(screen, "GAME OVER", 60, SCREEN_WIDTH //
                      2, SCREEN_HEIGHT//2 - 40, (255, 50, 50))
            draw_text(screen, f"最终得分: {score}", 40,
                      SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 20)
            draw_text(screen, "按 [空格] 重新开始", 25,
                      SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 70)

        pygame.display.flip()
        clock.tick(FPS)

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()
