import pygame
import sys
import random
import math

# 初始化
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("气动飞行模拟器 - 可正常升降")
clock = pygame.time.Clock()
FPS = 60

# 颜色定义
SKY_BLUE = (100, 180, 255)
CLOUD_WHITE = (240, 240, 240)
MOUNTAIN_GRAY = (80, 80, 80)
PLANE_BODY = (220, 30, 30)
PLANE_WING = (20, 20, 20)
PLANE_DETAIL = (245, 245, 245)
PROPELLER = (60, 60, 60)
STAR_YELLOW = (255, 220, 0)
HEART_RED = (255, 30, 30)
BLACK = (0, 0, 0)

# 全局物理参数
base_scroll_speed = 4
max_scroll_speed = 10
min_scroll_speed = 2
score = 0
lives = 3
game_over = False
game_pause = False
difficulty = 1

# 飞行物理常量
GRAVITY = 0.15
DRAG = 0.06
LIFT_COEFF = 0.22
MAX_PITCH = 25
PITCH_SPEED = 1.5
RETURN_SPEED = 0.4  # 姿态回正速度

# 飞机状态
plane_y_vel = 0
plane_pitch = 0
prop_angle = 0

# ===================== 飞机类 =====================
class Plane:
    def __init__(self):
        self.x = 120
        self.y = HEIGHT // 2

    def update(self, keys, scroll_spd):
        global plane_y_vel, plane_pitch, prop_angle
        if game_over or game_pause:
            return

        # 螺旋桨旋转
        prop_angle += 12

        # 修复：俯仰控制 + 姿态回正
        if keys[pygame.K_UP]:
            plane_pitch += PITCH_SPEED
        elif keys[pygame.K_DOWN]:
            plane_pitch -= PITCH_SPEED
        else:
            # 松开按键，姿态缓慢回中
            if plane_pitch > 0:
                plane_pitch -= RETURN_SPEED
            elif plane_pitch < 0:
                plane_pitch += RETURN_SPEED

        # 限制最大俯仰角
        plane_pitch = max(-MAX_PITCH, min(MAX_PITCH, plane_pitch))

        # 修复空气动力公式：负角度产生负升力，实现俯冲下降
        lift = scroll_spd * LIFT_COEFF * math.radians(plane_pitch)
        net_force = lift + GRAVITY
        plane_y_vel += net_force
        plane_y_vel *= (1 - DRAG)

        # 更新位置
        self.y += plane_y_vel

        # 边界限制
        if self.y < 20:
            self.y = 20
            plane_y_vel = 0
            plane_pitch = 0
        if self.y > HEIGHT - 40:
            self.y = HEIGHT - 40
            plane_y_vel = 0
            plane_pitch = 0

    def draw(self):
        rad = math.radians(plane_pitch)
        cx, cy = self.x, self.y

        # 机身
        body_points = [
            (cx - 35, cy),
            (cx + 30, cy - 8),
            (cx + 30, cy + 8),
            (cx - 35, cy)
        ]
        rot_body = [(
            (x - cx) * math.cos(rad) - (y - cy) * math.sin(rad) + cx,
            (x - cx) * math.sin(rad) + (y - cy) * math.cos(rad) + cy
        ) for x, y in body_points]
        pygame.draw.polygon(screen, PLANE_BODY, rot_body)

        # 上机翼
        wing1 = [(cx - 10, cy - 4), (cx - 10, cy - 22), (cx + 10, cy - 22), (cx + 10, cy - 4)]
        rot_wing1 = [(
            (x - cx) * math.cos(rad) - (y - cy) * math.sin(rad) + cx,
            (x - cx) * math.sin(rad) + (y - cy) * math.cos(rad) + cy
        ) for x, y in wing1]
        pygame.draw.polygon(screen, PLANE_WING, rot_wing1)

        # 下机翼
        wing2 = [(cx - 10, cy + 4), (cx - 10, cy + 22), (cx + 10, cy + 22), (cx + 10, cy + 4)]
        rot_wing2 = [(
            (x - cx) * math.cos(rad) - (y - cy) * math.sin(rad) + cx,
            (x - cx) * math.sin(rad) + (y - cy) * math.cos(rad) + cy
        ) for x, y in wing2]
        pygame.draw.polygon(screen, PLANE_WING, rot_wing2)

        # 尾翼
        tail_h = [(cx - 32, cy - 2), (cx - 42, cy - 8), (cx - 42, cy + 8), (cx - 32, cy + 2)]
        rot_tail = [(
            (x - cx) * math.cos(rad) - (y - cy) * math.sin(rad) + cx,
            (x - cx) * math.sin(rad) + (y - cy) * math.cos(rad) + cy
        ) for x, y in tail_h]
        pygame.draw.polygon(screen, PLANE_WING, rot_tail)

        # 机头
        nose_x = (cx + 30 - cx) * math.cos(rad) - (cy - cy) * math.sin(rad) + cx
        nose_y = (cx + 30 - cx) * math.sin(rad) + (cy - cy) * math.cos(rad) + cy
        pygame.draw.circle(screen, PLANE_DETAIL, (int(nose_x), int(nose_y)), 7)

        # 旋转螺旋桨
        r = 14
        p1_x = nose_x + r * math.cos(math.radians(prop_angle))
        p1_y = nose_y + r * math.sin(math.radians(prop_angle))
        p2_x = nose_x + r * math.cos(math.radians(prop_angle + 180))
        p2_y = nose_y + r * math.sin(math.radians(prop_angle + 180))
        pygame.draw.line(screen, PROPELLER, (nose_x, nose_y), (p1_x, p1_y), 3)
        pygame.draw.line(screen, PROPELLER, (nose_x, nose_y), (p2_x, p2_y), 3)

    def get_rect(self):
        return pygame.Rect(self.x - 45, self.y - 25, 75, 50)

# ===================== 云层障碍物 =====================
class Cloud:
    def __init__(self):
        self.x = WIDTH + random.randint(20, 100)
        self.y = random.randint(30, HEIGHT - 100)
        self.w = random.randint(60, 120)
        self.h = random.randint(30, 60)

    def update(self, spd):
        self.x -= spd * (1 + difficulty * 0.15)

    def draw(self):
        pygame.draw.ellipse(screen, CLOUD_WHITE, (self.x, self.y, self.w, self.h))

    def get_rect(self):
        return pygame.Rect(self.x, self.y, self.w, self.h)

# ===================== 山峰障碍物 =====================
class Mountain:
    def __init__(self):
        self.x = WIDTH + random.randint(30, 120)
        self.h = random.randint(80, 180)
        self.y = HEIGHT - self.h

    def update(self, spd):
        self.x -= spd * (1 + difficulty * 0.15)

    def draw(self):
        p1 = (self.x, HEIGHT)
        p2 = (self.x + 50, self.y)
        p3 = (self.x + 100, HEIGHT)
        pygame.draw.polygon(screen, MOUNTAIN_GRAY, [p1, p2, p3])

    def get_rect(self):
        return pygame.Rect(self.x, self.y, 100, self.h)

# ===================== 加分星星 =====================
class Star:
    def __init__(self):
        self.x = WIDTH + random.randint(10, 80)
        self.y = random.randint(40, HEIGHT - 80)
        self.r = 10

    def update(self, spd):
        self.x -= spd * (1 + difficulty * 0.15)

    def draw(self):
        pygame.draw.circle(screen, STAR_YELLOW, (self.x, self.y), self.r)

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

# ===================== 重置游戏 =====================
def reset_game():
    global plane, clouds, mountains, stars
    global score, lives, game_over, game_pause, difficulty
    global base_scroll_speed, plane_y_vel, plane_pitch, prop_angle

    plane = Plane()
    clouds = []
    mountains = []
    stars = []

    score = 0
    lives = 3
    base_scroll_speed = 4
    difficulty = 1
    game_over = False
    game_pause = False
    plane_y_vel = 0
    plane_pitch = 0
    prop_angle = 0

reset_game()

# 字体
font_small = pygame.font.Font(None, 26)
font_mid = pygame.font.Font(None, 36)
font_big = pygame.font.Font(None, 55)

# ===================== 主循环 =====================
while True:
    screen.fill(SKY_BLUE)
    keys = pygame.key.get_pressed()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE and not game_over:
                game_pause = not game_pause
            if event.key == pygame.K_r and game_over:
                reset_game()
            if event.key == pygame.K_RIGHT and base_scroll_speed < max_scroll_speed:
                base_scroll_speed += 1
            if event.key == pygame.K_LEFT and base_scroll_speed > min_scroll_speed:
                base_scroll_speed -= 1

    if not game_over and not game_pause:
        plane.update(keys, base_scroll_speed)
        difficulty = min(5, 1 + score // 500)

        if random.random() < 0.025 + difficulty * 0.008:
            clouds.append(Cloud())
        if random.random() < 0.015 + difficulty * 0.005:
            mountains.append(Mountain())
        if random.random() < 0.03:
            stars.append(Star())

        plane_rect = plane.get_rect()

        # 云层碰撞
        for c in clouds[:]:
            c.update(base_scroll_speed)
            if c.x + c.w < 0:
                clouds.remove(c)
                continue
            if plane_rect.colliderect(c.get_rect()):
                lives -= 1
                clouds.remove(c)
                if lives <= 0:
                    game_over = True

        # 山峰碰撞
        for m in mountains[:]:
            m.update(base_scroll_speed)
            if m.x + 100 < 0:
                mountains.remove(m)
                continue
            if plane_rect.colliderect(m.get_rect()):
                lives -= 1
                mountains.remove(m)
                if lives <= 0:
                    game_over = True

        # 收集星星
        for s in stars[:]:
            s.update(base_scroll_speed)
            if s.x + s.r < 0:
                stars.remove(s)
                continue
            if plane_rect.colliderect(s.get_rect()):
                score += 10
                stars.remove(s)

        score += 1

    # 绘制元素
    for c in clouds:
        c.draw()
    for m in mountains:
        m.draw()
    for s in stars:
        s.draw()
    plane.draw()

    # UI
    screen.blit(font_mid.render(f"Score: {score}", True, BLACK), (10, 10))
    screen.blit(font_small.render(f"Air Speed: {base_scroll_speed}", True, BLACK), (10, 45))
    screen.blit(font_small.render(f"Difficulty: {difficulty}", True, BLACK), (10, 70))
    screen.blit(font_small.render(f"Pitch: {int(plane_pitch)}°", True, BLACK), (10, 95))

    # 生命值
    for i in range(lives):
        pygame.draw.circle(screen, HEART_RED, (WIDTH - 30 - i * 25, 20), 10)

    # 暂停界面
    if game_pause and not game_over:
        overlay = pygame.Surface((WIDTH, HEIGHT))
        overlay.set_alpha(120)
        overlay.fill(BLACK)
        screen.blit(overlay, (0, 0))
        screen.blit(font_big.render("PAUSED", True, CLOUD_WHITE), (WIDTH//2 - 90, 220))
        screen.blit(font_mid.render("ESC to Resume", True, CLOUD_WHITE), (WIDTH//2 - 80, 300))

    # 游戏结束
    if game_over:
        overlay = pygame.Surface((WIDTH, HEIGHT))
        overlay.set_alpha(140)
        overlay.fill(BLACK)
        screen.blit(overlay, (0, 0))
        screen.blit(font_big.render("GAME OVER", True, HEART_RED), (WIDTH//2 - 110, 200))
        screen.blit(font_mid.render(f"Final Score: {score}", True, CLOUD_WHITE), (WIDTH//2 - 90, 280))
        screen.blit(font_mid.render("Press R to Restart", True, CLOUD_WHITE), (WIDTH//2 - 100, 340))

    pygame.display.update()
    clock.tick(FPS)