import pygame
import sys
import random
import math

# 初始化
pygame.init()
WIDTH, HEIGHT = 900, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("飞行模拟器")
clock = pygame.time.Clock()
FPS = 60

# 颜色
SKY_TOP = (30, 100, 200)
SKY_BOTTOM = (150, 200, 240)
CLOUD_WHITE = (255, 255, 255)
CLOUD_SHADOW = (220, 230, 240)
GROUND_GREEN = (80, 140, 60)
GROUND_DARK = (50, 100, 40)
PLANE_BODY = (200, 200, 210)
PLANE_DARK = (140, 140, 150)
PLANE_ACCENT = (220, 60, 60)
COCKPIT_BLUE = (100, 180, 255)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 230, 0)
RED = (255, 60, 60)
BIRD_DARK = (60, 60, 70)
MOUNTAIN_GRAY = (120, 130, 140)
MOUNTAIN_SNOW = (240, 245, 250)


class Plane:
    def __init__(self):
        self.x = WIDTH // 2
        self.y = HEIGHT // 2
        self.pitch = 0        # 俯仰角度（正=机头向上）
        self.roll = 0         # 滚转角度（正=右倾）
        self.speed = 5
        self.altitude = 1000  # 虚拟高度
        self.alive = True
        self.crashed_timer = 0

    def update(self, keys):
        if not self.alive:
            return

        # 俯仰控制（上下）
        pitch_input = 0
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            pitch_input = -1  # 机头抬起，屏幕上飞机向上
        elif keys[pygame.K_DOWN] or keys[pygame.K_s]:
            pitch_input = 1   # 机头向下

        # 滚转控制（左右）
        roll_input = 0
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            roll_input = -1
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            roll_input = 1

        # 平滑更新角度
        self.pitch += pitch_input * 2.5
        self.pitch *= 0.9  # 自动回正

        self.roll += roll_input * 3
        self.roll *= 0.88

        # 限制角度
        self.pitch = max(-40, min(40, self.pitch))
        self.roll = max(-50, min(50, self.roll))

        # 根据俯仰改变高度
        self.altitude += -self.pitch * 0.5

        # 限制屏幕内位置
        if self.y < 80:
            self.y = 80
        if self.y > HEIGHT - 100:
            self.y = HEIGHT - 100

        # 根据滚转横向移动（模拟转弯）
        self.x += self.roll * 0.05
        if self.x < 60:
            self.x = 60
        if self.x > WIDTH - 60:
            self.x = WIDTH - 60

        # 速度随俯仰变化
        self.speed = 5 + abs(self.pitch) * 0.05

    def crash(self):
        self.alive = False
        self.crashed_timer = 60

    def draw(self, surface):
        if not self.alive:
            # 坠毁状态
            cx, cy = self.x, self.y
            pygame.draw.circle(surface, PLANE_DARK, (int(cx), int(cy)), 20)
            pygame.draw.circle(surface, (255, 100, 0), (int(cx), int(cy)), 10)
            return

        # 根据滚转和俯仰计算飞机的屏幕偏移
        cx, cy = int(self.x), int(self.y)
        roll_rad = math.radians(self.roll)
        pitch_offset = self.pitch * 0.5

        # 绘制机身（俯视视角，带滚转效果）
        # 机身长度根据滚转略有透视变化
        plane_len = 50
        plane_wid = 12

        # 机身主体
        body_points = [
            (cx + math.cos(roll_rad) * plane_len / 2, cy - pitch_offset),
            (cx, cy + plane_wid),
            (cx - math.cos(roll_rad) * plane_len / 2, cy + pitch_offset),
            (cx, cy - plane_wid),
        ]
        pygame.draw.polygon(surface, PLANE_BODY, body_points)

        # 机翼
        wing_span = 70 * math.cos(roll_rad)
        wing_pts = [
            (cx, cy),
            (cx + wing_span / 2, cy + 15 - self.roll * 0.1),
            (cx, cy + 5),
            (cx - wing_span / 2, cy + 15 + self.roll * 0.1),
        ]
        pygame.draw.polygon(surface, PLANE_DARK, wing_pts)
        pygame.draw.polygon(surface, BLACK, wing_pts, 1)

        # 尾翼
        tail_pts = [
            (cx, cy + 20),
            (cx + 12, cy + 28),
            (cx - 12, cy + 28),
        ]
        pygame.draw.polygon(surface, PLANE_DARK, tail_pts)

        # 驾驶舱
        cockpit_offset = math.sin(roll_rad) * 5
        pygame.draw.ellipse(surface, COCKPIT_BLUE,
                            (cx - 8 + cockpit_offset, cy - 12 - pitch_offset,
                             16, 10))
        pygame.draw.ellipse(surface, BLACK,
                            (cx - 8 + cockpit_offset, cy - 12 - pitch_offset,
                             16, 10), 1)

        # 机头
        nose_pts = [
            (cx, cy - plane_wid),
            (cx + 4, cy - plane_wid - 8 - pitch_offset * 0.3),
            (cx - 4, cy - plane_wid - 8 - pitch_offset * 0.3),
        ]
        pygame.draw.polygon(surface, PLANE_ACCENT, nose_pts)

        # 尾焰
        flame_len = 8 + random.randint(0, 6)
        flame_pts = [
            (cx - 6, cy + 28),
            (cx, cy + 28 + flame_len),
            (cx + 6, cy + 28),
        ]
        pygame.draw.polygon(surface, (255, 140, 0), flame_pts)
        pygame.draw.polygon(surface, (255, 220, 0), [
            (cx - 3, cy + 28),
            (cx, cy + 28 + flame_len * 0.6),
            (cx + 3, cy + 28),
        ])


class Cloud:
    def __init__(self, x, y, size):
        self.x = x
        self.y = y
        self.size = size
        self.points = []
        for i in range(4):
            self.points.append((
                random.uniform(-size, size),
                random.uniform(-size * 0.3, size * 0.3)
            ))

    def update(self, speed):
        self.y += speed * 0.4
        if self.y > HEIGHT + 100:
            self.y = -100
            self.x = random.randint(0, WIDTH)

    def get_rect(self):
        r = self.size
        return pygame.Rect(self.x - r, self.y - r * 0.4, r * 2, r * 0.8)

    def draw(self, surface):
        r = self.size
        for dx, dy in self.points:
            pygame.draw.circle(surface, CLOUD_SHADOW,
                               (int(self.x + dx), int(self.y + dy + 3)), int(r * 0.5))
        for dx, dy in self.points:
            pygame.draw.circle(surface, CLOUD_WHITE,
                               (int(self.x + dx), int(self.y + dy)), int(r * 0.5))


class Bird:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.phase = random.uniform(0, math.pi * 2)
        self.wing_speed = random.uniform(0.15, 0.25)
        self.speed = random.uniform(2, 4)

    def update(self):
        self.x -= self.speed
        self.phase += self.wing_speed
        if self.x < -50:
            self.x = WIDTH + 50
            self.y = random.randint(100, HEIGHT - 150)

    def get_rect(self):
        return pygame.Rect(self.x - 12, self.y - 8, 24, 16)

    def draw(self, surface):
        wing_offset = math.sin(self.phase) * 8
        # 身体
        pygame.draw.ellipse(surface, BIRD_DARK,
                            (self.x - 6, self.y - 3, 12, 6))
        # 翅膀
        pygame.draw.line(surface, BIRD_DARK,
                         (self.x, self.y), (self.x - 10, self.y - wing_offset), 3)
        pygame.draw.line(surface, BIRD_DARK,
                         (self.x, self.y), (self.x + 10, self.y - wing_offset), 3)


class Mountain:
    def __init__(self, x, height, width):
        self.x = x
        self.height = height
        self.width = width

    def draw(self, surface):
        base_y = HEIGHT - 40
        peak_y = base_y - self.height
        pygame.draw.polygon(surface, MOUNTAIN_GRAY, [
            (self.x - self.width / 2, base_y),
            (self.x, peak_y),
            (self.x + self.width / 2, base_y)
        ])
        # 雪顶
        snow_h = self.height * 0.25
        snow_w = self.width * 0.25
        pygame.draw.polygon(surface, MOUNTAIN_SNOW, [
            (self.x - snow_w / 2, peak_y + snow_h),
            (self.x, peak_y),
            (self.x + snow_w / 2, peak_y + snow_h)
        ])


def draw_background(surface, altitude, distance):
    # 天空渐变（根据高度变化）
    alt_ratio = max(0, min(1, (altitude - 500) / 3000))
    top_color = (
        int(30 + alt_ratio * 20),
        int(100 - alt_ratio * 40),
        int(200 + alt_ratio * 40)
    )
    bottom_color = (
        int(150 - alt_ratio * 30),
        int(200 - alt_ratio * 20),
        int(240)
    )

    for y in range(HEIGHT):
        t = y / HEIGHT
        color = (
            int(top_color[0] * (1 - t) + bottom_color[0] * t),
            int(top_color[1] * (1 - t) + bottom_color[1] * t),
            int(top_color[2] * (1 - t) + bottom_color[2] * t),
        )
        pygame.draw.line(surface, color, (0, y), (WIDTH, y))

    # 太阳
    sun_x = WIDTH - 120
    sun_y = 80
    pygame.draw.circle(surface, (255, 250, 200), (sun_x, sun_y), 50)
    pygame.draw.circle(surface, (255, 255, 240), (sun_x, sun_y), 40)

    # 云层下方地面（仅在低空可见）
    if altitude < 1200:
        ground_alpha = max(0, min(255, int((1200 - altitude) / 2)))
        ground_surface = pygame.Surface((WIDTH, 80), pygame.SRCALPHA)
        ground_surface.fill((*GROUND_GREEN, ground_alpha))
        surface.blit(ground_surface, (0, HEIGHT - 80))

        # 地平线
        pygame.draw.line(surface, GROUND_DARK,
                         (0, HEIGHT - 80), (WIDTH, HEIGHT - 80), 2)


def draw_ui(surface, plane, font, small_font, distance):
    # 高度计
    alt_text = small_font.render(f"ALT: {int(plane.altitude)} m", True, BLACK)
    surface.blit(alt_text, (20, 20))

    # 速度表
    speed_text = small_font.render(f"SPD: {int(plane.speed * 40)} km/h", True, BLACK)
    surface.blit(speed_text, (20, 50))

    # 距离
    dist_text = font.render(f"Distance: {int(distance)} m", True, BLACK)
    surface.blit(dist_text, (WIDTH - 320, 20))

    # 姿态仪（简易）
    cx, cy = 80, HEIGHT - 80
    pygame.draw.circle(surface, BLACK, (cx, cy), 45, 2)
    # 地平线
    pitch_px = int(plane.pitch * 1.2)
    roll_rad = math.radians(-plane.roll)
    line_len = 35
    dx = math.cos(roll_rad) * line_len
    dy = math.sin(roll_rad) * line_len
    pygame.draw.line(surface, (100, 180, 100),
                     (cx - dx, cy + pitch_px - dy),
                     (cx + dx, cy + pitch_px + dy), 2)
    # 飞机符号
    pygame.draw.line(surface, YELLOW, (cx - 15, cy), (cx + 15, cy), 3)
    pygame.draw.line(surface, YELLOW, (cx, cy - 5), (cx, cy + 5), 3)
    # 角度标记
    angle_text = small_font.render(
        f"P:{int(plane.pitch)}° R:{int(plane.roll)}°", True, BLACK)
    surface.blit(angle_text, (cx - 60, cy + 55))

    # 操作提示
    hint = small_font.render("W/S or ↑/↓ : Pitch    A/D or ←/→ : Roll",
                             True, (60, 60, 60))
    surface.blit(hint, (WIDTH // 2 - 200, HEIGHT - 25))

    # 游戏结束
    if not plane.alive:
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 140))
        surface.blit(overlay, (0, 0))

        go_text = font.render("CRASHED!", True, RED)
        surface.blit(go_text, (WIDTH // 2 - 100, HEIGHT // 2 - 80))

        final_dist = small_font.render(
            f"Distance flown: {int(distance)} meters", True, WHITE)
        surface.blit(final_dist, (WIDTH // 2 - 150, HEIGHT // 2 - 20))

        restart = small_font.render("Press R to Restart", True, YELLOW)
        surface.blit(restart, (WIDTH // 2 - 110, HEIGHT // 2 + 30))


def main():
    font = pygame.font.SysFont("arial", 36, bold=True)
    small_font = pygame.font.SysFont("arial", 20)

    plane = Plane()
    clouds = [Cloud(random.randint(100, WIDTH - 100),
                    random.randint(50, HEIGHT - 150),
                    random.randint(40, 90)) for _ in range(6)]
    birds = []
    mountains = [Mountain(x, random.randint(150, 300), random.randint(150, 250))
                 for x in [100, 350, 600, 850]]
    distance = 0
    bird_timer = 0

    running = True
    while running:
        clock.tick(FPS)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r and not plane.alive:
                    plane = Plane()
                    clouds = [Cloud(random.randint(100, WIDTH - 100),
                                    random.randint(50, HEIGHT - 150),
                                    random.randint(40, 90)) for _ in range(6)]
                    birds = []
                    distance = 0
                    bird_timer = 0

        keys = pygame.key.get_pressed()

        if plane.alive:
            plane.update(keys)
            distance += plane.speed * 0.1

            # 更新云
            for cloud in clouds:
                cloud.update(plane.speed)
                # 碰撞云层（只减速，不坠毁）
                if cloud.get_rect().colliderect(
                        pygame.Rect(plane.x - 20, plane.y - 20, 40, 40)):
                    plane.speed = max(3, plane.speed - 0.1)

            # 生成鸟
            bird_timer += 1
            if bird_timer > random.randint(60, 120):
                bird_timer = 0
                birds.append(Bird(WIDTH + 50, random.randint(100, HEIGHT - 150)))

            # 更新鸟
            for bird in birds[:]:
                bird.update()
                if bird.x < -60:
                    birds.remove(bird)
                # 碰撞检测
                if bird.get_rect().colliderect(
                        pygame.Rect(plane.x - 15, plane.y - 15, 30, 30)):
                    plane.crash()

            # 高度过低坠毁
            if plane.altitude < 0:
                plane.crash()

        # 绘制
        draw_background(screen, plane.altitude, distance)

        # 远山
        for m in mountains:
            m.draw(screen)

        # 云
        for cloud in clouds:
            cloud.draw(screen)

        # 鸟
        for bird in birds:
            bird.draw(screen)

        # 飞机
        plane.draw(screen)

        # UI
        draw_ui(screen, plane, font, small_font, distance)

        pygame.display.flip()

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()