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 = (135, 206, 250)
SNOW_WHITE = (245, 245, 255)
SNOW_SHADOW = (220, 225, 240)
TREE_GREEN = (34, 100, 50)
TREE_DARK = (20, 60, 30)
ROCK_GRAY = (110, 110, 120)
ROCK_DARK = (80, 80, 90)
SKIER_RED = (220, 40, 40)
SKIER_BLUE = (40, 80, 200)
SKIER_SKIN = (255, 220, 177)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 230, 0)

# 游戏参数
BASE_SPEED = 6
MAX_SPEED = 18
SPEED_ACCEL = 0.003
STEER_SPEED = 7
OBSTACLE_SPAWN_INTERVAL = 40  # 帧


class Skier:
    def __init__(self):
        self.x = WIDTH // 2
        self.y = HEIGHT - 150
        self.width = 30
        self.height = 40
        self.speed = BASE_SPEED
        self.distance = 0
        self.alive = True
        self.lean = 0  # 倾斜角度，用于视觉
        self.crashed_timer = 0

    def update(self, keys):
        if not self.alive:
            return
        # 加速
        self.speed = min(MAX_SPEED, self.speed + SPEED_ACCEL)
        self.distance += self.speed / 10

        # 左右移动
        dx = 0
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            dx = -STEER_SPEED
            self.lean = max(-1, self.lean - 0.15)
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            dx = STEER_SPEED
            self.lean = min(1, self.lean + 0.15)
        else:
            self.lean *= 0.85

        self.x += dx
        # 边界限制
        if self.x < 30:
            self.x = 30
        if self.x > WIDTH - 30:
            self.x = WIDTH - 30

    def get_rect(self):
        return pygame.Rect(self.x - self.width // 2, self.y - self.height, self.width, self.height)

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

    def draw(self, surface):
        rect = self.get_rect()
        if not self.alive:
            # 摔倒的样子
            pygame.draw.ellipse(surface, SKIER_RED, (rect.x - 10, rect.y + 15, 50, 25))
            pygame.draw.ellipse(surface, SKIER_SKIN, (rect.x + 20, rect.y + 10, 18, 18))
            return

        # 滑雪板
        skew = int(self.lean * 6)
        pygame.draw.line(surface, BLACK, (rect.x + 2 - skew, rect.y + self.height),
                         (rect.x + 2 + skew, rect.y + self.height + 8), 4)
        pygame.draw.line(surface, BLACK, (rect.x + self.width - 2 - skew, rect.y + self.height),
                         (rect.x + self.width - 2 + skew, rect.y + self.height + 8), 4)

        # 身体
        body_rect = pygame.Rect(rect.x + 5, rect.y + 8, 20, 25)
        pygame.draw.rect(surface, SKIER_BLUE, body_rect)

        # 头
        head_center = (rect.x + 15 + skew, rect.y + 8)
        pygame.draw.circle(surface, SKIER_SKIN, head_center, 9)

        # 帽子
        pygame.draw.arc(surface, SKIER_RED, (head_center[0] - 10, head_center[1] - 10, 20, 15),
                        0, math.pi, 6)

        # 护目镜
        pygame.draw.rect(surface, BLACK, (head_center[0] - 7, head_center[1] - 3, 14, 5))
        pygame.draw.rect(surface, (100, 200, 255), (head_center[0] - 6, head_center[1] - 2, 12, 3))

        # 滑雪杖
        pole_x = rect.x + (2 if self.lean <= 0 else self.width - 2)
        pygame.draw.line(surface, (200, 200, 200),
                         (pole_x, rect.y + 12),
                         (pole_x - self.lean * 10, rect.y + self.height + 5), 2)


class Obstacle:
    def __init__(self, x, y, kind):
        self.x = x
        self.y = y
        self.kind = kind  # 'tree' 或 'rock'
        self.width = 24 if kind == 'tree' else 30
        self.height = 40 if kind == 'tree' else 24
        self.scale = random.uniform(0.8, 1.3)
        self.passed = False

    def get_rect(self):
        return pygame.Rect(self.x - self.width * self.scale / 2,
                           self.y - self.height * self.scale,
                           self.width * self.scale,
                           self.height * self.scale)

    def update(self, speed):
        self.y -= speed

    def draw(self, surface):
        rect = self.get_rect()
        if self.kind == 'tree':
            # 树干
            pygame.draw.rect(surface, (90, 50, 20),
                             (rect.x + rect.width // 2 - 3, rect.bottom - 10, 6, 10))
            # 树冠（三层）
            cx = rect.x + rect.width // 2
            for i, ratio in enumerate([1.0, 0.75, 0.5]):
                tri_h = rect.height * 0.5 * ratio
                tri_w = rect.width * ratio
                top_y = rect.bottom - 10 - tri_h * (i + 1) + tri_h * 0.4
                pygame.draw.polygon(surface, TREE_GREEN, [
                    (cx, top_y - tri_h),
                    (cx - tri_w / 2, top_y),
                    (cx + tri_w / 2, top_y)
                ])
                pygame.draw.polygon(surface, TREE_DARK, [
                    (cx, top_y - tri_h),
                    (cx - tri_w / 2, top_y),
                    (cx + tri_w / 2, top_y)
                ], 2)
        else:
            # 岩石
            pygame.draw.ellipse(surface, ROCK_GRAY, rect)
            pygame.draw.ellipse(surface, ROCK_DARK, rect, 2)
            # 高光
            pygame.draw.ellipse(surface, (160, 160, 170),
                                (rect.x + rect.width * 0.2, rect.y + rect.height * 0.2,
                                 rect.width * 0.3, rect.height * 0.3))


class SnowParticle:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.vx = random.uniform(-2, 2)
        self.vy = random.uniform(-4, -1)
        self.life = random.randint(20, 40)
        self.size = random.randint(2, 4)

    def update(self, speed):
        self.x += self.vx
        self.y += self.vy - speed * 0.3
        self.life -= 1

    def draw(self, surface):
        if self.life > 0:
            alpha = max(0, self.life / 40)
            color = (int(255 * alpha), int(255 * alpha), int(255 * alpha))
            pygame.draw.circle(surface, color, (int(self.x), int(self.y)), self.size)


def draw_background(surface, distance):
    surface.fill(SKY_BLUE)

    # 远山
    mountain_offset = (distance * 0.5) % 400
    for i in range(-1, 4):
        base_x = i * 300 - mountain_offset
        pygame.draw.polygon(surface, (180, 200, 220), [
            (base_x, 250), (base_x + 150, 100), (base_x + 300, 250)
        ])
        # 雪顶
        pygame.draw.polygon(surface, WHITE, [
            (base_x + 120, 140), (base_x + 150, 100), (base_x + 180, 140),
            (base_x + 165, 135), (base_x + 150, 155), (base_x + 135, 135)
        ])

    # 雪地
    snow_rect = pygame.Rect(0, 250, WIDTH, HEIGHT - 250)
    pygame.draw.rect(surface, SNOW_WHITE, snow_rect)

    # 雪坡纹理（斜线模拟滑过的痕迹）
    for i in range(20):
        y = 260 + i * 18
        offset = (distance * 2 + i * 37) % WIDTH
        pygame.draw.line(surface, SNOW_SHADOW, (offset - 100, y), (offset + 50, y), 2)


def draw_ui(surface, skier, font, small_font):
    # 速度条
    speed_ratio = (skier.speed - BASE_SPEED) / (MAX_SPEED - BASE_SPEED)
    bar_x, bar_y = 20, 20
    pygame.draw.rect(surface, (60, 60, 60), (bar_x, bar_y, 200, 20))
    pygame.draw.rect(surface, (100, 200, 255), (bar_x, bar_y, int(200 * speed_ratio), 20))
    pygame.draw.rect(surface, BLACK, (bar_x, bar_y, 200, 20), 2)
    speed_text = small_font.render(f"Speed: {int(skier.speed * 5)} km/h", True, BLACK)
    surface.blit(speed_text, (bar_x, bar_y + 24))

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

    # 操作提示
    hint = small_font.render("Use A/D or ←/→ to steer", True, (80, 80, 80))
    surface.blit(hint, (WIDTH // 2 - 120, HEIGHT - 30))

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

        go_text = font.render("CRASH!", True, (255, 60, 60))
        surface.blit(go_text, (WIDTH // 2 - 80, HEIGHT // 2 - 80))

        dist_final = small_font.render(f"You skied {int(skier.distance)} meters", True, WHITE)
        surface.blit(dist_final, (WIDTH // 2 - 130, HEIGHT // 2 - 20))

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


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

    skier = Skier()
    obstacles = []
    particles = []
    spawn_counter = 0
    game_over_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 skier.alive:
                    skier = Skier()
                    obstacles = []
                    particles = []
                    spawn_counter = 0
                    game_over_timer = 0

        keys = pygame.key.get_pressed()

        if skier.alive:
            skier.update(keys)

            # 生成障碍物
            spawn_counter += 1
            if spawn_counter >= OBSTACLE_SPAWN_INTERVAL:
                spawn_counter = 0
                # 随机位置，避免太靠边
                obs_x = random.randint(60, WIDTH - 60)
                obs_y = HEIGHT + 40
                kind = random.choice(['tree', 'tree', 'tree', 'rock'])
                obstacles.append(Obstacle(obs_x, obs_y, kind))

            # 更新障碍物
            for obs in obstacles[:]:
                obs.update(skier.speed)
                if obs.y < -60:
                    obstacles.remove(obs)

            # 生成雪花粒子（滑雪时扬起的雪）
            if random.random() < 0.6:
                particles.append(SnowParticle(
                    skier.x + random.uniform(-15, 15),
                    skier.y + skier.height - 5
                ))

            # 碰撞检测
            skier_rect = skier.get_rect()
            for obs in obstacles:
                if skier_rect.colliderect(obs.get_rect()):
                    skier.crash()
                    break

            # 更新粒子
            for p in particles[:]:
                p.update(skier.speed)
                if p.life <= 0:
                    particles.remove(p)

        else:
            game_over_timer += 1

        # 绘制
        draw_background(screen, skier.distance)

        # 绘制障碍物（按y排序，远的先画）
        for obs in sorted(obstacles, key=lambda o: o.y):
            obs.draw(screen)

        # 绘制粒子
        for p in particles:
            p.draw(screen)

        # 绘制滑雪者
        skier.draw(screen)

        # UI
        draw_ui(screen, skier, font, small_font)

        pygame.display.flip()

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()