import tkinter as tk
import random
import math
import time

# ========================
# 游戏配置
# ========================
WIDTH, HEIGHT = 800, 600
GRAVITY = 0.35
MAX_SPEED = 18
FRICTION = 0.98
TREE_RADIUS = 18
GATE_W = 60
SKIER_W, SKIER_H = 20, 40

# ========================
# 主题
# ========================
THEMES = {
    "❄️ 雪山经典": {"bg_top": "#87CEEB", "bg_bot": "#B0E0E6", "snow": "#FFFFFF", "tree": "#228B22", "tree_dark": "#006400", "gate_r": "#FF0000", "gate_b": "#0000FF", "skier": "#FF0000", "skier_alt": "#FFFFFF", "trail": "#D0D0D0", "rock": "#808080"},
    "🌙 夜滑模式": {"bg_top": "#0D1B2A", "bg_bot": "#1B2838", "snow": "#E0E8F0", "tree": "#1A4A2A", "tree_dark": "#0D2B18", "gate_r": "#FF4444", "gate_b": "#4444FF", "skier": "#FFD700", "skier_alt": "#FFA500", "trail": "#2A3A4A", "rock": "#404040"},
    "🌅 夕阳滑道": {"bg_top": "#FF7E5F", "bg_bot": "#FEB47B", "snow": "#FFF5EE", "tree": "#2E8B57", "tree_dark": "#1B5E20", "gate_r": "#8B0000", "gate_b": "#191970", "skier": "#FFD700", "skier_alt": "#000000", "trail": "#E8C4A0", "rock": "#5C4033"},
    "🌸 樱花雪道": {"bg_top": "#FFD6E8", "bg_bot": "#FFE8F0", "snow": "#FFF0F5", "tree": "#4A9B6E", "tree_dark": "#2E6B4A", "gate_r": "#C2185B", "gate_b": "#7B1FA2", "skier": "#E91E63", "skier_alt": "#FF80AB", "trail": "#F8BBD0", "rock": "#A1887F"},
    "🔥 熔岩雪道": {"bg_top": "#2C0000", "bg_bot": "#4A0000", "snow": "#FFE4E1", "tree": "#1A0000", "tree_dark": "#0D0000", "gate_r": "#FF4500", "gate_b": "#FFD700", "skier": "#00FF7F", "skier_alt": "#00CED1", "trail": "#3D1C1C", "rock": "#1A0000"},
    "🌈 彩虹雪国": {"bg_top": "#A8E6CF", "bg_bot": "#DCEDC1", "snow": "#FFFFFF", "tree": "#FF8B94", "tree_dark": "#D65A71", "gate_r": "#FF6B6B", "gate_b": "#4ECDC4", "skier": "#FFE66D", "skier_alt": "#FF6B6B", "trail": "#C7ECEA", "rock": "#95A5A6"},
}
cur_theme = "❄️ 雪山经典"

# ========================
# 全局状态
# ========================
root = None
canvas = None
lbl_speed = None
lbl_score = None
lbl_time = None
lbl_lives = None
lbl_msg = None
theme_btns = []
all_widgets = []

skier = None
trees = []
gates = []
rocks = []
snowflakes = []
trail_particles = []
gate_passed = []
game_running = True
game_over = False
paused = False
score = 0
lives = 3
start_time = 0
elapsed = 0
difficulty = 1.0
distance = 0
last_gate = -1
combo = 0
best_score = 0

# ========================
# 工具函数
# ========================
def clamp(v, lo, hi):
    return max(lo, min(hi, v))

def dist(ax, ay, bx, by):
    return math.sqrt((ax - bx) ** 2 + (ay - by) ** 2)

def circle_rect(cx, cy, cr, rx, ry, rw, rh):
    """圆与矩形碰撞"""
    closest_x = clamp(cx, rx, rx + rw)
    closest_y = clamp(cy, ry, ry + rh)
    return dist(cx, cy, closest_x, closest_y) < cr

# ========================
# 雪道生成
# ========================
def generate_track():
    global trees, gates, rocks, snowflakes, gate_passed, last_gate, difficulty
    trees.clear()
    gates.clear()
    rocks.clear()
    snowflakes.clear()
    gate_passed.clear()
    last_gate = -1
    difficulty = 1.0

    # 雪道两侧树（随机分布）
    for i in range(120):
        side = random.choice([-1, 1])
        tx = WIDTH // 2 + side * random.randint(180, 380)
        ty = random.randint(-200, HEIGHT + 200)
        trees.append({"x": tx, "y": ty, "size": random.randint(20, 35), "type": random.choice(["pine", "pine2"])})

    # 旗门（成对出现，形成赛道）
    gate_x_center = WIDTH // 2
    for i in range(40):
        gy = -i * 180 - 100
        offset = random.randint(-60, 60)
        gates.append({
            "x": gate_x_center + offset - GATE_W // 2,
            "y": gy,
            "w": GATE_W,
            "h": 6,
            "passed": False,
            "id": i
        })

    # 岩石障碍
    for i in range(25):
        rx = random.randint(100, WIDTH - 100)
        ry = random.randint(-300, HEIGHT + 100)
        rocks.append({"x": rx, "y": ry, "r": random.randint(12, 22)})

    # 雪花
    for i in range(80):
        snowflakes.append({
            "x": random.randint(0, WIDTH),
            "y": random.randint(0, HEIGHT),
            "speed": random.uniform(1, 4),
            "size": random.uniform(1, 3),
            "wobble": random.uniform(0, math.pi * 2)
        })

def reset_game():
    global skier, score, lives, game_over, paused, start_time, distance, combo, elapsed
    skier = {
        "x": WIDTH // 2,
        "y": HEIGHT // 2 - 50,
        "vx": 0,
        "vy": 0,
        "speed": 0,
        "angle": 0,
        "tilt": 0,
        "invincible": 0,
        "crouch": False,
        "jump": 0,
        "anim": 0,
    }
    score = 0
    lives = 3
    game_over = False
    paused = False
    start_time = time.time()
    distance = 0
    combo = 0
    elapsed = 0
    generate_track()

# ========================
# 更新逻辑
# ========================
def update():
    global score, lives, game_over, difficulty, distance, combo, elapsed, last_gate

    if not skier or paused or game_over:
        return

    elapsed = time.time() - start_time
    difficulty = 1.0 + elapsed / 60.0  # 每分钟难度+1

    keys = root.keys_pressed if hasattr(root, 'keys_pressed') else set()

    # ---- 输入 ----
    turn = 0
    if "a" in keys or "Left" in keys:
        turn = -1
    elif "d" in keys or "Right" in keys:
        turn = 1

    crouch = "Down" in keys or "s" in keys
    jumping = "space" in keys or "Up" in keys or "w" in keys

    skier["crouch"] = crouch
    skier["anim"] += 0.3 if abs(skier["vx"]) > 2 else 0.1

    # ---- 转向 ----
    skier["vx"] += turn * 0.6 * difficulty
    skier["vx"] *= FRICTION
    skier["vx"] = clamp(skier["vx"], -10, 10)

    # ---- 前进速度 ----
    target_speed = 6 + difficulty * 1.5
    if crouch:
        target_speed *= 1.4
    skier["vy"] = target_speed
    skier["speed"] = math.sqrt(skier["vx"] ** 2 + skier["vy"] ** 2)

    # ---- 跳跃 ----
    if jumping and skier["jump"] == 0:
        skier["jump"] = 25
    if skier["jump"] > 0:
        skier["jump"] -= 1.2
        if skier["jump"] < 0:
            skier["jump"] = 0

    # ---- 移动 ----
    skier["x"] += skier["vx"]
    skier["y"] += skier["vy"] * 0.3  # 视觉上移（实际是雪道下移）

    # 边界
    margin = 60
    skier["x"] = clamp(skier["x"], margin, WIDTH - margin)

    # ---- 雪道下移（相机）----
    camera_speed = skier["vy"]
    distance += camera_speed * 0.1

    for t in trees:
        t["y"] += camera_speed
    for g in gates:
        g["y"] += camera_speed
    for r in rocks:
        r["y"] += camera_speed
    for s in snowflakes:
        s["y"] += s["speed"] + camera_speed * 0.3
        s["x"] += math.sin(s["wobble"]) * 0.5
        s["wobble"] += 0.05
        if s["y"] > HEIGHT + 10:
            s["y"] = -10
            s["x"] = random.randint(0, WIDTH)
    for tp in trail_particles[:]:
        tp["y"] += camera_speed
        tp["life"] -= 1
        if tp["life"] <= 0:
            trail_particles.remove(tp)

    # ---- 生成拖尾粒子 ----
    if random.random() < 0.4:
        trail_particles.append({
            "x": skier["x"] + random.uniform(-6, 6),
            "y": skier["y"] + SKIER_H // 2,
            "life": 20,
            "max_life": 20,
            "size": random.uniform(2, 4)
        })

    # ---- 回收离开屏幕的物体 ----
    trees[:] = [t for t in trees if t["y"] < HEIGHT + 60]
    gates[:] = [g for g in gates if g["y"] < HEIGHT + 60]
    rocks[:] = [r for r in rocks if r["y"] < HEIGHT + 60]

    # ---- 生成新物体（前方）----
    while len(trees) < 120:
        side = random.choice([-1, 1])
        trees.append({
            "x": WIDTH // 2 + side * random.randint(180, 380),
            "y": random.randint(-400, -50),
            "size": random.randint(20, 35),
            "type": random.choice(["pine", "pine2"])
        })
    while len(gates) < 40:
        gy = min(g["y"] for g in gates) - random.randint(150, 220) if gates else -100
        offset = random.randint(-60, 60)
        gates.append({
            "x": WIDTH // 2 + offset - GATE_W // 2,
            "y": gy,
            "w": GATE_W,
            "h": 6,
            "passed": False,
            "id": len(gates)
        })
    while len(rocks) < 25:
        rocks.append({
            "x": random.randint(100, WIDTH - 100),
            "y": random.randint(-400, -50),
            "r": random.randint(12, 22)
        })

    # ---- 旗门检测 ----
    for g in gates:
        if g["passed"]:
            continue
        # 旗门中心
        gcx = g["x"] + g["w"] / 2
        gcy = g["y"] + g["h"] / 2
        if dist(skier["x"], skier["y"], gcx, gcy) < 35:
            g["passed"] = True
            gate_passed.append(g["id"])
            combo += 1
            gate_score = 100 * combo
            score += gate_score
            spawn_particles(gcx, gcy, "#FFD700", 12)
            last_gate = g["id"]

    # 检查是否漏门（从下方经过但未穿过）
    for g in gates:
        if not g["passed"] and g["y"] > skier["y"] + 50:
            g["passed"] = True  # 标记为已处理
            combo = 0  # 断连击

    # ---- 树碰撞 ----
    if skier["invincible"] <= 0 and skier["jump"] == 0:
        for t in trees:
            if dist(skier["x"], skier["y"], t["x"], t["y"]) < t["size"] * 0.6 + 10:
                hit_obstacle("🌲 撞树了！")
                break

    # ---- 岩石碰撞 ----
    if skier["invincible"] <= 0 and skier["jump"] == 0:
        for r in rocks:
            if dist(skier["x"], skier["y"], r["x"], r["y"]) < r["r"] + 8:
                hit_obstacle("🪨 撞石头了！")
                break

    # ---- 无敌计时 ----
    if skier["invincible"] > 0:
        skier["invincible"] -= 1

    # ---- 得分（距离分）----
    score += int(camera_speed * 0.5)

    # ---- 检查终点 ----
    if distance > 5000:
        game_over = True

def hit_obstacle(msg):
    global lives, combo
    lives -= 1
    combo = 0
    skier["invincible"] = 90  # 1.5秒无敌
    spawn_particles(skier["x"], skier["y"], "#FF0000", 15)
    flash_msg(msg)
    if lives <= 0:
        global game_over
        game_over = True

# ========================
# 粒子
# ========================
def spawn_particles(x, y, color, count=10):
    for _ in range(count):
        angle = random.uniform(0, math.pi * 2)
        speed = random.uniform(1, 5)
        trail_particles.append({
            "x": x,
            "y": y,
            "vx": math.cos(angle) * speed,
            "vy": math.sin(angle) * speed,
            "life": random.randint(15, 30),
            "max_life": 30,
            "size": random.uniform(2, 5),
            "color": color
        })

# ========================
# 消息闪烁
# ========================
msg_text = ""
msg_timer = 0

def flash_msg(text):
    global msg_text, msg_timer
    msg_text = text
    msg_timer = 60

# ========================
# 绘制
# ========================
def draw():
    canvas.delete("all")
    theme = THEMES[cur_theme]

    # ---- 渐变天空/背景 ----
    for i in range(HEIGHT):
        ratio = i / HEIGHT
        # 简单双色渐变
        r = int((0x87 if cur_theme == "❄️ 雪山经典" else 0x0D) * (1 - ratio) + (0xB0 if cur_theme == "❄️ 雪山经典" else 0x1B) * ratio)
        # 用主题色
        pass

    # 直接用主题色画背景
    canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=theme["bg_top"], outline="")
    # 下半部分稍深
    canvas.create_rectangle(0, HEIGHT // 2, WIDTH, HEIGHT, fill=theme["bg_bot"], outline="")

    # ---- 远山剪影 ----
    for mx in range(-200, WIDTH + 200, 350):
        offset = (distance * 0.1) % 350
        wx = mx + offset
        canvas.create_polygon(
            wx - 120, HEIGHT - 80,
            wx, HEIGHT - 80 - 150,
            wx + 120, HEIGHT - 80,
            fill=theme["trail"], outline=""
        )

    # ---- 雪花 ----
    for s in snowflakes:
        alpha_hex = hex(min(255, int(150 + s["speed"] * 30)))[2:].zfill(2)
        canvas.create_oval(s["x"] - s["size"], s["y"] - s["size"],
                            s["x"] + s["size"], s["y"] + s["size"],
                            fill="#FFFFFF", outline="")

    # ---- 雪道边缘 ----
    canvas.create_rectangle(0, 0, 50, HEIGHT, fill=theme["tree_dark"], outline="")
    canvas.create_rectangle(WIDTH - 50, 0, WIDTH, HEIGHT, fill=theme["tree_dark"], outline="")

    # ---- 旗门 ----
    for g in gates:
        if g["y"] < -20 or g["y"] > HEIGHT + 20:
            continue
        # 杆
        canvas.create_line(g["x"], g["y"], g["x"], g["y"] - 30, fill=theme["gate_r"], width=3)
        canvas.create_line(g["x"] + g["w"], g["y"], g["x"] + g["w"], g["y"] - 30, fill=theme["gate_b"], width=3)
        # 横幅
        flag_color = theme["gate_r"] if not g["passed"] else "#888888"
        canvas.create_rectangle(g["x"], g["y"] - 30, g["x"] + g["w"], g["y"] - 24,
                                fill=flag_color, outline="")
        # 旗帜
        canvas.create_polygon(g["x"], g["y"] - 30, g["x"] + 12, g["y"] - 24, g["x"], g["y"] - 18,
                                fill=flag_color, outline="")
        canvas.create_polygon(g["x"] + g["w"], g["y"] - 30, g["x"] + g["w"] - 12, g["y"] - 24,
                                g["x"] + g["w"], g["y"] - 18,
                                fill=theme["gate_b"] if not g["passed"] else "#888888", outline="")

        # 编号
        if not g["passed"]:
            canvas.create_text(g["x"] + g["w"] // 2, g["y"] - 15, text=str(g["id"] + 1),
                                font=("", 8), fill="#FFFFFF")

    # ---- 树 ----
    for t in trees:
        if t["y"] < -40 or t["y"] > HEIGHT + 40:
            continue
        sz = t["size"]
        # 树干
        canvas.create_rectangle(t["x"] - 3, t["y"], t["x"] + 3, t["y"] + sz * 0.5,
                                fill="#8B4513", outline="")
        # 三层树冠
        for layer, (dy, w, h) in enumerate([(0, sz, sz * 0.8), (sz * 0.4, sz * 0.8, sz * 0.6), (sz * 0.8, sz * 0.6, sz * 0.4)]):
            y_top = t["y"] - dy - h
            canvas.create_polygon(
                t["x"] - w, t["y"] - dy,
                t["x"] + w, t["y"] - dy,
                t["x"], y_top,
                fill=theme["tree"] if layer == 0 else theme["tree_dark"], outline=""
            )
        # 雪顶
        canvas.create_polygon(
            t["x"] - sz * 0.3, t["y"] - sz * 0.8,
            t["x"] + sz * 0.3, t["y"] - sz * 0.8,
            t["x"], t["y"] - sz * 1.0,
            fill=theme["snow"], outline=""
        )

    # ---- 岩石 ----
    for r in rocks:
        if r["y"] < -30 or r["y"] > HEIGHT + 30:
            continue
        canvas.create_oval(r["x"] - r["r"], r["y"] - r["r"], r["x"] + r["r"], r["y"] + r["r"],
                            fill=theme["rock"], outline="#404040")
        # 高光
        canvas.create_oval(r["x"] - r["r"] * 0.5, r["y"] - r["r"] * 0.6,
                            r["x"] + r["r"] * 0.1, r["y"] - r["r"] * 0.1,
                            fill="#A0A0A0", outline="")

    # ---- 拖尾粒子 ----
    for tp in trail_particles:
        if tp["life"] <= 0:
            continue
        alpha = tp["life"] / tp["max_life"]
        sz = tp["size"] * alpha
        canvas.create_oval(tp["x"] - sz, tp["y"] - sz, tp["x"] + sz, tp["y"] + sz,
                            fill=theme["snow"], outline="")

    # ---- 滑雪者 ----
    if skier:
        sx = skier["x"]
        sy = skier["y"]
        jumping = skier["jump"] > 0
        flash = skier["invincible"] > 0 and (skier["invincible"] // 4) % 2 == 0

        # 阴影
        if not jumping:
            canvas.create_oval(sx - 12, sy + SKIER_H // 2 - 2, sx + 12, sy + SKIER_H // 2 + 4,
                                fill="#00000030", outline="")

        # 跳跃偏移
        jy = -skier["jump"] if jumping else 0

        if not flash:
            # 身体
            body_color = theme["skier"]
            alt_color = theme["skier_alt"]

            # 头
            canvas.create_oval(sx - 7, sy - SKIER_H // 2 + jy, sx + 7, sy - SKIER_H // 2 + 14 + jy,
                                fill=alt_color, outline="")
            # 头盔/帽子
            canvas.create_arc(sx - 7, sy - SKIER_H // 2 - 2 + jy, sx + 7, sy - SKIER_H // 2 + 6 + jy,
                                start=0, extent=180, fill=body_color, outline="")
            # 护目镜
            canvas.create_rectangle(sx - 5, sy - SKIER_H // 2 + 5 + jy, sx + 5, sy - SKIER_H // 2 + 9 + jy,
                                    fill="#1A1A1A", outline="")
            canvas.create_rectangle(sx - 4, sy - SKIER_H // 2 + 6 + jy, sx + 4, sy - SKIER_H // 2 + 8 + jy,
                                    fill="#00BFFF", outline="")

            # 身体（弯腰姿势）
            lean = skier["vx"] * 1.5
            canvas.create_polygon(
                sx - 6 + lean * 0.3, sy - SKIER_H // 2 + 12 + jy,
                sx + 6 + lean * 0.3, sy - SKIER_H // 2 + 12 + jy,
                sx + 8 + lean * 0.8, sy + SKIER_H // 2 - 8 + jy,
                sx - 4 + lean * 0.8, sy + SKIER_H // 2 - 8 + jy,
                fill=body_color, outline=""
            )

            # 手臂（摆臂动画）
            arm_swing = math.sin(skier["anim"]) * 8
            canvas.create_line(sx + lean * 0.5, sy - 5 + jy, sx + 10 + lean + arm_swing, sy + 5 + jy,
                                fill=alt_color, width=3)
            canvas.create_line(sx + lean * 0.5, sy - 5 + jy, sx - 10 + lean - arm_swing, sy + 5 + jy,
                                fill=alt_color, width=3)

            # 滑雪板
            if not jumping:
                board_len = 18
                canvas.create_rectangle(sx - board_len + lean, sy + SKIER_H // 2 - 4,
                                        sx + board_len + lean, sy + SKIER_H // 2 + 2,
                                        fill="#FFD700", outline="#B8860B")
                canvas.create_rectangle(sx - board_len + lean + 2, sy + SKIER_H // 2 - 2,
                                        sx + board_len + lean - 2, sy + SKIER_H // 2,
                                        fill="#FFF8DC", outline="")

                # 雪雾
                for _ in range(2):
                    fx = sx + random.uniform(-board_len, board_len) + lean
                    fy = sy + SKIER_H // 2 + random.uniform(0, 6)
                    canvas.create_oval(fx - 3, fy - 2, fx + 3, fy + 2,
                                        fill=theme["snow"], outline="")

    # ---- HUD ----
    # 左上：速度
    speed_kmh = int(skier["speed"] * 5) if skier else 0
    canvas.create_rectangle(10, 10, 160, 55, fill="#00000080", outline="")
    canvas.create_text(85, 22, text=f"⚡ {speed_kmh} km/h", font=("Consolas", 13, "bold"), fill="#00FF00")
    canvas.create_text(85, 42, text=f"📏 {int(distance)}m", font=("Consolas", 10), fill="#FFFFFF")

    # 右上：分数和生命
    canvas.create_rectangle(WIDTH - 200, 10, WIDTH - 10, 75, fill="#00000080", outline="")
    canvas.create_text(WIDTH - 105, 25, text=f"🏆 {score}", font=("Consolas", 13, "bold"), fill="#FFD700")
    canvas.create_text(WIDTH - 105, 45, text=f"❤️ {lives}", font=("Consolas", 12), fill="#FF4444")
    canvas.create_text(WIDTH - 105, 62, text=f"🔥 x{combo}", font=("Consolas", 10), fill="#FF8C00")

    # 时间
    t = int(elapsed)
    canvas.create_text(WIDTH // 2, 20, text=f"⏱️ {t}s", font=("Consolas", 12, "bold"), fill="#FFFFFF")

    # 难度条
    diff_pct = min(1.0, (difficulty - 1.0) / 3.0)
    bar_w = 200
    canvas.create_rectangle(WIDTH // 2 - bar_w // 2, 35, WIDTH // 2 + bar_w // 2, 42, fill="#333333", outline="")
    canvas.create_rectangle(WIDTH // 2 - bar_w // 2, 35, WIDTH // 2 - bar_w // 2 + int(bar_w * diff_pct), 42,
                            fill="#FF4500" if diff_pct > 0.6 else "#FFD700", outline="")
    canvas.create_text(WIDTH // 2, 50, text=f"难度 {difficulty:.1f}x", font=("Consolas", 8), fill="#FFFFFF")

    # 消息
    global msg_timer
    if msg_timer > 0:
        alpha = min(255, msg_timer * 4)
        canvas.create_text(WIDTH // 2, HEIGHT // 2 - 80, text=msg_text,
                            font=("Comic Sans MS", 18, "bold"), fill="#FF0000")
        msg_timer -= 1

    # 暂停
    if paused:
        canvas.create_rectangle(WIDTH // 2 - 100, HEIGHT // 2 - 40, WIDTH // 2 + 100, HEIGHT // 2 + 40,
                                fill="#000000CC", outline="#FFFFFF", width=2)
        canvas.create_text(WIDTH // 2, HEIGHT // 2, text="⏸️ 暂停", font=("Comic Sans MS", 20, "bold"), fill="#FFFFFF")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 25, text="按 P 继续", font=("Comic Sans MS", 10), fill="#AAAAAA")

    # Game Over
    if game_over:
        canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill="#000000AA", outline="")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 - 40, text="🏁 滑行结束！" if distance > 5000 else "💀 摔倒了！",
                            font=("Comic Sans MS", 28, "bold"), fill="#FFD700")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 5, text=f"总分: {score}", font=("Comic Sans MS", 18), fill="#FFFFFF")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 35, text=f"距离: {int(distance)}m  旗门: {len(gate_passed)}", font=("Comic Sans MS", 13), fill="#CCCCCC")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 65, text="按 R 重新开始", font=("Comic Sans MS", 12), fill="#FFD700")

# ========================
# 主循环
# ========================
def game_loop():
    if not game_running:
        return
    if skier and not game_over:
        update()
    draw()

    # HUD 更新
    if lbl_speed: lbl_speed.config(text=f"⚡ {int((skier['speed'] if skier else 0) * 5)} km/h")
    if lbl_score: lbl_score.config(text=f"🏆 {score}")
    if lbl_time: lbl_time.config(text=f"⏱️ {int(elapsed)}s")
    if lbl_lives: lbl_lives.config(text=f"❤️ {lives}")

    root.after(16, game_loop)  # ~60 FPS

# ========================
# 输入
# ========================
def key_down(e):
    global paused, game_over
    keys = root.keys_pressed

    if e.keysym in ("r", "R"):
        if game_over:
            reset_game()
            return

    if e.keysym in ("p", "P"):
        paused = not paused
        return

    keys.add(e.keysym)

def key_up(e):
    keys = root.keys_pressed
    keys.discard(e.keysym)

# ========================
# 换肤
# ========================
def apply_theme(name):
    global cur_theme
    cur_theme = name
    theme = THEMES[name]
    root.configure(bg=theme["bg_top"])
    for w in all_widgets:
        try:
            w.configure(bg=theme["bg_top"])
        except:
            pass
    for btn in theme_btns:
        try:
            btn.configure(bg=theme["gate_r"], fg="white")
        except:
            pass

# ========================
# 构建界面
# ========================
def build_ui():
    global root, canvas, lbl_speed, lbl_score, lbl_time, lbl_lives, lbl_msg
    global theme_btns, all_widgets

    root = tk.Tk()
    root.title("⛷️ 滑雪模拟器")
    root.resizable(False, False)
    root.keys_pressed = set()

    # HUD 栏
    hud = tk.Frame(root)
    hud.pack(fill="x")

    lbl_speed = tk.Label(hud, text="⚡ 0 km/h", font=("Consolas", 11, "bold"))
    lbl_speed.pack(side="left", padx=10)

    lbl_score = tk.Label(hud, text="🏆 0", font=("Consolas", 11))
    lbl_score.pack(side="left", padx=10)

    lbl_time = tk.Label(hud, text="⏱️ 0s", font=("Consolas", 11))
    lbl_time.pack(side="left", padx=10)

    lbl_lives = tk.Label(hud, text="❤️ 3", font=("Consolas", 11))
    lbl_lives.pack(side="left", padx=10)

    lbl_msg = tk.Label(hud, text="A/D 转向 | S/↓ 蹲伏加速 | Space/↑ 跳跃 | P 暂停", font=("Comic Sans MS", 9))
    lbl_msg.pack(side="right", padx=10)

    # 主题栏
    theme_bar = tk.Frame(root)
    theme_bar.pack(fill="x")
    for name in THEMES:
        btn = tk.Button(theme_bar, text=name, font=("Comic Sans MS", 8, "bold"),
                         relief="raised", bd=1, padx=3,
                         command=lambda n=name: apply_theme(n))
        btn.pack(side="left", padx=1)
        theme_btns.append(btn)

    # 画布
    canvas_frame = tk.Frame(root)
    canvas_frame.pack()
    canvas = tk.Canvas(canvas_frame, width=WIDTH, height=HEIGHT, highlightthickness=0)
    canvas.pack()

    # 底部提示
    bottom = tk.Frame(root)
    bottom.pack(fill="x")
    tk.Label(bottom, text="⛷️ 穿越旗门得分 · 避开树木岩石 · 蹲伏加速 · 跳跃无敌", font=("Comic Sans MS", 9)).pack()

    all_widgets.extend([hud, theme_bar, canvas_frame, bottom, lbl_msg])

# ========================
# 启动
# ========================
if __name__ == "__main__":
    build_ui()
    apply_theme("❄️ 雪山经典")
    reset_game()
    root.bind("<KeyPress>", key_down)
    root.bind("<KeyRelease>", key_up)
    root.after(100, game_loop)
    root.mainloop()
