import tkinter as tk
import random
import math
import time

# ========================
# 游戏配置
# ========================
WIDTH, HEIGHT = 900, 480
GRAVITY = 0.6
JUMP_POWER = -12
MOVE_SPEED = 4
MAX_FALL = 12

# ========================
# 主题
# ========================
THEMES = {
    "🍄 经典蘑菇":  {"bg": "#5C94FC", "brick": "#C84C0C", "brick_top": "#E08040", "pipe": "#00A800", "pipe_top": "#00D800", "ground": "#C08040", "ground_dark": "#A06020", "bg_detail": "#3A6FBF"},
    "🌙 暗夜模式": {"bg": "#1A1A3E", "brick": "#8B2500", "brick_top": "#B03030", "pipe": "#006400", "pipe_top": "#008000", "ground": "#3D2B1A", "ground_dark": "#2A1B0E", "bg_detail": "#0F0F2A"},
    "🌸 樱花世界": {"bg": "#FFD6E8", "brick": "#D4508A", "brick_top": "#F080B0", "pipe": "#50C878", "pipe_top": "#80E8A0", "ground": "#D4A76A", "ground_dark": "#B08850", "bg_detail": "#FFB0D0"},
    "🔥 烈焰熔岩": {"bg": "#8B0000", "brick": "#B03000", "brick_top": "#D04020", "pipe": "#FF4500", "pipe_top": "#FF6347", "ground": "#4A0000", "ground_dark": "#2A0000", "bg_detail": "#600000"},
    "❄️ 冰雪王国": {"bg": "#87CEEB", "brick": "#4682B4", "brick_top": "#5F9EA0", "pipe": "#2E8B57", "pipe_top": "#3CB371", "ground": "#F0F8FF", "ground_dark": "#D0E0F0", "bg_detail": "#5BA3D9"},
    "🌈 彩虹乐园": {"bg": "#FF69B4", "brick": "#FF1493", "brick_top": "#FF69B4", "pipe": "#32CD32", "pipe_top": "#7CFC00", "ground": "#FFD700", "ground_dark": "#DAA520", "bg_detail": "#FF4500"},
}
cur_theme = "🍄 经典蘑菇"

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

player = None
platforms = []
coins = []
enemies = []
mushrooms = []
particles = []
stars_bg = []

game_running = True
game_over = False
game_won = False
score = 0
coins_count = 0
lives = 3
time_left = 300
start_time = 0
last_frame = 0
map_width = 0

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

def aabb(a, b):
    return (a["x"] < b["x"] + b["w"] and a["x"] + a["w"] > b["x"] and
            a["y"] < b["y"] + b["h"] and a["y"] + a["h"] > b["y"])

# ========================
# 关卡地图
# ========================
def build_level():
    global platforms, coins, enemies, mushrooms, map_width
    platforms.clear()
    coins.clear()
    enemies.clear()
    mushrooms.clear()

    theme = THEMES[cur_theme]
    ground_y = HEIGHT - 48
    map_width = 3000

    # ---- 地面 ----
    for x in range(0, map_width, 32):
        platforms.append({"x": x, "y": ground_y, "w": 32, "h": 48, "type": "ground"})
        platforms.append({"x": x, "y": ground_y + 16, "w": 32, "h": 32, "type": "ground_dark"})

    # ---- 砖块行 ----
    def add_brick_row(y, start, end, gap_start=0, gap_end=0):
        for x in range(start, end, 32):
            if gap_start <= x < gap_end:
                continue
            platforms.append({"x": x, "y": y, "w": 32, "h": 32, "type": "brick"})
            if random.random() < 0.15:
                coins.append({"x": x + 8, "y": y - 24, "r": 8, "alive": True, "bob": random.uniform(0, math.pi * 2)})

    # 第1层砖块
    add_brick_row(ground_y - 96, 300, 700)
    add_brick_row(ground_y - 96, 900, 1300)
    add_brick_row(ground_y - 96, 1500, 1900)
    add_brick_row(ground_y - 96, 2100, 2600)
    add_brick_row(ground_y - 96, 2700, 3000)

    # 第2层砖块（更高）
    add_brick_row(ground_y - 192, 500, 800)
    add_brick_row(ground_y - 192, 1100, 1400)
    add_brick_row(ground_y - 192, 1700, 2000)
    add_brick_row(ground_y - 192, 2300, 2600)

    # ---- 管道 ----
    def add_pipe(x, h=2):
        px = x
        py = ground_y - h * 32
        platforms.append({"x": px, "y": py, "w": 48, "h": h * 32, "type": "pipe"})
        platforms.append({"x": px - 4, "y": py, "w": 56, "h": 16, "type": "pipe_top"})

    add_pipe(600, 2)
    add_pipe(1050, 3)
    add_pipe(1600, 2)
    add_pipe(2200, 4)
    add_pipe(2650, 2)

    # ---- 悬空平台 ----
    def add_platform(x, y, w):
        for i in range(w):
            platforms.append({"x": x + i * 32, "y": y, "w": 32, "h": 16, "type": "brick"})
            if random.random() < 0.2:
                coins.append({"x": x + i * 32 + 16, "y": y - 20, "r": 8, "alive": True, "bob": random.uniform(0, math.pi * 2)})

    add_platform(400, ground_y - 144, 3)
    add_platform(750, ground_y - 200, 2)
    add_platform(1200, ground_y - 160, 4)
    add_platform(1400, ground_y - 240, 2)
    add_platform(1800, ground_y - 144, 3)
    add_platform(2000, ground_y - 200, 2)
    add_platform(2450, ground_y - 160, 4)
    add_platform(2800, ground_y - 240, 3)

    # ---- 地面金币 ----
    for x in range(100, map_width, random.randint(120, 200)):
        coins.append({"x": x, "y": ground_y - 40, "r": 8, "alive": True, "bob": random.uniform(0, math.pi * 2)})

    # ---- 敌人 (Goomba) ----
    enemy_spots = [350, 550, 800, 1000, 1150, 1350, 1550, 1750, 1950, 2150, 2400, 2600, 2850]
    for ex in enemy_spots:
        enemies.append({
            "x": ex, "y": ground_y - 28, "w": 28, "h": 28,
            "vx": random.choice([-1.5, -1, 1, 1.5]),
            "alive": True, "squish": 0,
            "type": "goomba"
        })

    # ---- 蘑菇（变大道具）----
    mush_spots = [450, 950, 1700, 2500]
    for mx in mush_spots:
        mushrooms.append({
            "x": mx, "y": ground_y - 40, "w": 24, "h": 24,
            "alive": True, "vy": 0, "bob": 0
        })

# ========================
# 玩家
# ========================
def create_player():
    global player
    player = {
        "x": 50, "y": HEIGHT - 48 - 40, "w": 24, "h": 36,
        "vx": 0, "vy": 0, "on_ground": False,
        "facing": "right", "big": False,
        "invincible": 0, "anim": 0, "walking": False,
        "jump_pressed": False
    }

# ========================
# 更新逻辑
# ========================
def update_player():
    p = player
    if not p:
        return

    # 输入
    keys = root.keys_pressed if hasattr(root, 'keys_pressed') else set()
    if "a" in keys or "Left" in keys:
        p["vx"] = -MOVE_SPEED
        p["facing"] = "left"
        p["walking"] = True
    elif "d" in keys or "Right" in keys:
        p["vx"] = MOVE_SPEED
        p["facing"] = "right"
        p["walking"] = True
    else:
        p["vx"] = 0
        p["walking"] = False

    # 跳跃
    if ("w" in keys or "space" in keys or "Up" in keys):
        if p["on_ground"] and not p["jump_pressed"]:
            p["vy"] = JUMP_POWER
            p["on_ground"] = False
            p["jump_pressed"] = True
    else:
        p["jump_pressed"] = False

    # 重力
    p["vy"] += GRAVITY
    p["vy"] = min(p["vy"], MAX_FALL)

    # 移动 + 碰撞
    # X 轴
    p["x"] += p["vx"]
    for plat in platforms:
        if plat["type"] in ("pipe_top",):
            continue
        if aabb(p, plat):
            if p["vx"] > 0:
                p["x"] = plat["x"] - p["w"]
            elif p["vx"] < 0:
                p["x"] = plat["x"] + plat["w"]
            p["vx"] = 0

    # Y 轴
    p["y"] += p["vy"]
    p["on_ground"] = False
    for plat in platforms:
        if aabb(p, plat):
            if p["vy"] > 0:
                p["y"] = plat["y"] - p["h"]
                p["vy"] = 0
                p["on_ground"] = True
            elif p["vy"] < 0:
                p["y"] = plat["x"] + plat["h"]  # not used; correct:
                p["y"] = plat["y"] + plat["h"]
                p["vy"] = 0

    # 边界
    p["x"] = clamp(p["x"], 0, map_width - p["w"])
    if p["y"] > HEIGHT:
        die()

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

    # 动画
    p["anim"] += 0.2 if p["walking"] else 0.05

def update_coins():
    global score
    p = player
    for c in coins:
        if not c["alive"]:
            continue
        c["bob"] += 0.1
        # 碰撞
        cx = c["x"] + c["r"]
        cy = c["y"] + c["r"] + math.sin(c["bob"]) * 3
        if (p["x"] < cx < p["x"] + p["w"] and
            p["y"] < cy < p["y"] + p["h"]):
            c["alive"] = False
            global coins_count
            coins_count += 1
            score += 100
            spawn_particles(cx, cy, "#FFD700", 8)

def update_enemies():
    global score, lives
    p = player
    for e in enemies:
        if not e["alive"]:
            continue
        if e["squish"] > 0:
            e["squish"] += 1
            if e["squish"] > 30:
                e["alive"] = False
            continue

        # 移动
        e["x"] += e["vx"]
        # 碰到墙反弹
        for plat in platforms:
            if plat["type"] == "ground" or plat["type"] == "pipe":
                if aabb(e, plat):
                    e["vx"] *= -1
                    e["x"] += e["vx"] * 2
                    break

        # 碰到玩家
        if aabb(p, e):
            if p["invincible"] > 0:
                continue
            # 从上方踩
            if p["vy"] > 0 and p["y"] + p["h"] - p["vy"] <= e["y"] + 8:
                e["squish"] = 1
                p["vy"] = JUMP_POWER * 0.7
                score += 200
                spawn_particles(e["x"] + 14, e["y"] + 14, "#8B4513", 10)
            else:
                # 受伤
                if p["big"]:
                    p["big"] = False
                    p["h"] = 28
                    p["invincible"] = 90
                    spawn_particles(p["x"] + 12, p["y"] + 14, "#FF0000", 12)
                else:
                    die()

def update_mushrooms():
    p = player
    for m in mushrooms:
        if not m["alive"]:
            continue
        # 重力
        m["vy"] += GRAVITY * 0.5
        m["vy"] = min(m["vy"], MAX_FALL * 0.5)
        m["y"] += m["vy"]
        m["bob"] += 0.05

        # 地面碰撞
        for plat in platforms:
            if plat["type"] == "ground":
                if aabb(m, plat):
                    m["y"] = plat["y"] - m["h"]
                    m["vy"] = 0

        # 吃蘑菇
        if aabb(p, m):
            m["alive"] = False
            p["big"] = True
            p["h"] = 48
            p["invincible"] = 60
            global score
            score += 500
            spawn_particles(p["x"] + 12, p["y"] + 24, "#FF4500", 15)

def update_particles():
    for pt in particles[:]:
        pt["x"] += pt["vx"]
        pt["y"] += pt["vy"]
        pt["vy"] += 0.2
        pt["life"] -= 1
        if pt["life"] <= 0:
            particles.remove(pt)

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

def die():
    global lives, game_over
    lives -= 1
    if lives <= 0:
        game_over = True
    else:
        # 重生
        create_player()
        player["invincible"] = 120

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

    cam_x = clamp(player["x"] - WIDTH // 3, 0, max(0, map_width - WIDTH)) if player else 0

    # ---- 背景 ----
    canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=theme["bg"], outline="")

    # 远处山丘
    for mx in range(-100, WIDTH + 200, 300):
        wx = mx + (cam_x * 0.2) % 300
        canvas.create_polygon(
            wx - 80, HEIGHT - 48,
            wx, HEIGHT - 48 - 100,
            wx + 80, HEIGHT - 48,
            fill=theme["bg_detail"], outline=""
        )
    # 近处山丘
    for mx in range(-150, WIDTH + 200, 400):
        wx = mx + (cam_x * 0.4) % 400
        canvas.create_polygon(
            wx - 100, HEIGHT - 48,
            wx, HEIGHT - 48 - 140,
            wx + 100, HEIGHT - 48,
            fill=theme["bg_detail"], outline=""
        )

    # 云朵
    cloud_data = [(120, 60), (350, 40), (600, 80), (800, 50)]
    for cx, cy in cloud_data:
        wx = (cx - cam_x * 0.15) % (WIDTH + 200) - 100
        for dx, dy, r in [(0, 0, 22), (-18, 5, 16), (18, 5, 16), (-8, -8, 14), (8, -8, 14)]:
            canvas.create_oval(wx + dx - r, cy + dy - r, wx + dx + r, cy + dy + r,
                                fill="#FFFFFF", outline="")

    # ---- 地面 ----
    for plat in platforms:
        wx = plat["x"] - cam_x
        if wx + plat["w"] < 0 or wx > WIDTH:
            continue
        t = plat["type"]
        if t == "ground":
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + plat["h"],
                                    fill=theme["ground"], outline="#00000020")
            # 草皮
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + 6,
                                    fill=theme["brick_top"], outline="")
        elif t == "ground_dark":
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + plat["h"],
                                    fill=theme["ground_dark"], outline="")
        elif t == "brick":
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + plat["h"],
                                    fill=theme["brick"], outline="#00000030")
            # 砖缝
            canvas.create_line(wx + plat["w"] // 2, plat["y"], wx + plat["w"] // 2, plat["y"] + plat["h"],
                                fill="#00000040", width=1)
        elif t == "pipe":
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + plat["h"],
                                    fill=theme["pipe"], outline="#00000040")
            # 高光
            canvas.create_rectangle(wx + 4, plat["y"] + 4, wx + 10, plat["y"] + plat["h"] - 4,
                                    fill=theme["pipe_top"], outline="")
        elif t == "pipe_top":
            canvas.create_rectangle(wx, plat["y"], wx + plat["w"], plat["y"] + plat["h"],
                                    fill=theme["pipe_top"], outline="#00000040")
            canvas.create_line(wx + 4, plat["y"] + 4, wx + plat["w"] - 4, plat["y"] + 4,
                                fill="#FFFFFF40", width=2)

    # ---- 金币 ----
    for c in coins:
        if not c["alive"]:
            continue
        wx = c["x"] - cam_x
        if wx < -20 or wx > WIDTH:
            continue
        bob_y = c["y"] + math.sin(c["bob"]) * 3
        # 金币（椭圆模拟3D旋转）
        scale = abs(math.cos(c["bob"]))
        w = max(2, int(c["r"] * scale))
        canvas.create_oval(wx + c["r"] - w, bob_y, wx + c["r"] + w, bob_y + c["r"] * 2,
                            fill="#FFD700", outline="#B8860B")
        if scale > 0.5:
            canvas.create_text(wx + c["r"], bob_y + c["r"], text="$", font=("", 8, "bold"), fill="#B8860B")

    # ---- 蘑菇 ----
    for m in mushrooms:
        if not m["alive"]:
            continue
        wx = m["x"] - cam_x
        # 蘑菇帽
        canvas.create_oval(wx, m["y"], wx + m["w"], m["y"] + m["h"] * 0.6,
                            fill="#FF4500", outline="")
        # 白点
        for dx, dy in [(6, 4), (14, 3), (10, 8), (18, 10)]:
            canvas.create_oval(wx + dx - 2, m["y"] + dy - 2, wx + dx + 2, m["y"] + dy + 2,
                                fill="#FFFFFF", outline="")
        # 蘑菇茎
        canvas.create_rectangle(wx + 6, m["y"] + m["h"] * 0.5, wx + m["w"] - 6, m["y"] + m["h"],
                                fill="#FFDEAD", outline="")
        # 眼睛
        canvas.create_oval(wx + 8, m["y"] + m["h"] * 0.65, wx + 12, m["y"] + m["h"] * 0.8, fill="#000")
        canvas.create_oval(wx + 14, m["y"] + m["h"] * 0.65, wx + 18, m["y"] + m["h"] * 0.8, fill="#000")

    # ---- 敌人 (Goomba) ----
    for e in enemies:
        if not e["alive"]:
            continue
        wx = e["x"] - cam_x
        if e["squish"] > 0:
            # 被踩扁
            canvas.create_oval(wx, e["y"] + e["h"] - 8, wx + e["w"], e["y"] + e["h"],
                                fill="#8B4513", outline="")
            continue
        # 身体
        canvas.create_oval(wx, e["y"], wx + e["w"], e["y"] + e["h"],
                            fill="#8B4513", outline="#5C2E0B", width=2)
        # 眉毛
        canvas.create_arc(wx + 2, e["y"] + 4, wx + e["w"] // 2, e["y"] + 12,
                            start=0, extent=180, fill="#5C2E0B", outline="")
        canvas.create_arc(wx + e["w"] // 2, e["y"] + 4, wx + e["w"] - 2, e["y"] + 12,
                            start=0, extent=180, fill="#5C2E0B", outline="")
        # 眼睛
        canvas.create_oval(wx + 6, e["y"] + 10, wx + 12, e["y"] + 16, fill="#FFF", outline="")
        canvas.create_oval(wx + e["w"] - 12, e["y"] + 10, wx + e["w"] - 6, e["y"] + 16, fill="#FFF", outline="")
        canvas.create_oval(wx + 8, e["y"] + 12, wx + 11, e["y"] + 15, fill="#000")
        canvas.create_oval(wx + e["w"] - 11, e["y"] + 12, wx + e["w"] - 8, e["y"] + 15, fill="#000")
        # 脚
        canvas.create_oval(wx + 2, e["y"] + e["h"] - 6, wx + 10, e["y"] + e["h"] + 2, fill="#5C2E0B")
        canvas.create_oval(wx + e["w"] - 10, e["y"] + e["h"] - 6, wx + e["w"] - 2, e["y"] + e["h"] + 2, fill="#5C2E0B")

    # ---- 玩家 (Mario) ----
    if player:
        wx = player["x"] - cam_x
        wy = player["y"]
        flashing = player["invincible"] > 0 and (player["invincible"] // 4) % 2 == 0
        if not flashing:
            draw_mario(wx, wy, player["facing"], player["big"], player["walking"], player["anim"])

    # ---- 粒子 ----
    for pt in particles:
        wx = pt["x"] - cam_x
        alpha = max(50, pt["life"] * 8)
        canvas.create_oval(wx - pt["size"], pt["y"] - pt["size"],
                            wx + pt["size"], pt["y"] + pt["size"],
                            fill=pt["color"], outline="")

    # ---- HUD ----
    # 分数
    canvas.create_text(10, 10, anchor="nw", text=f"分数: {score}", font=("Comic Sans MS", 14, "bold"), fill="#FFFFFF")
    canvas.create_text(10, 30, anchor="nw", text=f"🪙 金币: {coins_count}", font=("Comic Sans MS", 12), fill="#FFD700")
    canvas.create_text(10, 50, anchor="nw", text=f"❤️ 生命: {lives}", font=("Comic Sans MS", 12), fill="#FF4444")

    # 时间
    elapsed = (time.time() - start_time) if start_time else 0
    t_left = max(0, time_left - int(elapsed))
    canvas.create_text(WIDTH - 10, 10, anchor="ne", text=f"⏱️ {t_left}s", font=("Comic Sans MS", 14, "bold"), fill="#FFFFFF")

    # 提示
    if lbl_msg_text:
        canvas.create_text(WIDTH // 2, 80, text=lbl_msg_text, font=("Comic Sans MS", 13, "bold"), fill="#FFFF00")

    # Game Over
    if game_over:
        canvas.create_rectangle(WIDTH // 2 - 150, HEIGHT // 2 - 50, WIDTH // 2 + 150, HEIGHT // 2 + 50,
                                fill="#000000CC", outline="#FF0000", width=3)
        canvas.create_text(WIDTH // 2, HEIGHT // 2 - 15, text="💀 GAME OVER", font=("Comic Sans MS", 24, "bold"), fill="#FF0000")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 20, text="按 R 重新开始", font=("Comic Sans MS", 12), fill="#FFFFFF")

    # Win
    if game_won:
        canvas.create_rectangle(WIDTH // 2 - 150, HEIGHT // 2 - 50, WIDTH // 2 + 150, HEIGHT // 2 + 50,
                                fill="#000000CC", outline="#FFD700", width=3)
        canvas.create_text(WIDTH // 2, HEIGHT // 2 - 15, text="🏆 YOU WIN!", font=("Comic Sans MS", 24, "bold"), fill="#FFD700")
        canvas.create_text(WIDTH // 2, HEIGHT // 2 + 20, text=f"分数: {score}", font=("Comic Sans MS", 14), fill="#FFFFFF")

def draw_mario(x, y, facing, big, walking, anim):
    """画马里奥"""
    # 颜色
    hat_color = "#FF0000"
    skin = "#FFDCA8"
    overalls = "#0000FF"
    shoe = "#8B4513"

    h = 48 if big else 36
    w = 24

    # 身体缩放
    s = h / 36

    # ---- 鞋子 ----
    sy = y + h - 4 * s
    canvas.create_rectangle(x + 2 * s, sy, x + 10 * s, sy + 4 * s, fill=shoe, outline="")
    canvas.create_rectangle(x + 14 * s, sy, x + 22 * s, sy + 4 * s, fill=shoe, outline="")

    # ---- 背带裤 ----
    canvas.create_rectangle(x + 2 * s, y + 16 * s, x + 22 * s, y + h - 2 * s, fill=overalls, outline="")
    # 纽扣
    canvas.create_oval(x + 6 * s, y + 20 * s, x + 10 * s, y + 24 * s, fill="#FFD700", outline="")
    canvas.create_oval(x + 14 * s, y + 20 * s, x + 18 * s, y + 24 * s, fill="#FFD700", outline="")

    # ---- 手臂 ----
    arm_swing = math.sin(anim) * 4 if walking else 0
    canvas.create_rectangle(x - 2 * s, y + 16 * s + arm_swing, x + 6 * s, y + 28 * s + arm_swing, fill=skin, outline="")
    canvas.create_rectangle(x + 20 * s, y + 16 * s - arm_swing, x + 26 * s, y + 28 * s - arm_swing, fill=skin, outline="")

    # ---- 头 ----
    head_y = y + 2 * s
    canvas.create_oval(x + 2 * s, head_y, x + 22 * s, head_y + 16 * s, fill=skin, outline="")
    # 胡子
    canvas.create_rectangle(x + 6 * s, head_y + 10 * s, x + 18 * s, head_y + 14 * s, fill="#8B4513", outline="")
    # 眼睛
    if facing == "right":
        canvas.create_oval(x + 12 * s, head_y + 5 * s, x + 17 * s, head_y + 10 * s, fill="#FFFFFF", outline="")
        canvas.create_oval(x + 14 * s, head_y + 6 * s, x + 16 * s, head_y + 9 * s, fill="#000000")
    else:
        canvas.create_oval(x + 7 * s, head_y + 5 * s, x + 12 * s, head_y + 10 * s, fill="#FFFFFF", outline="")
        canvas.create_oval(x + 8 * s, head_y + 6 * s, x + 10 * s, head_y + 9 * s, fill="#000000")

    # ---- 帽子 ----
    canvas.create_rectangle(x + 2 * s, head_y, x + 22 * s, head_y + 6 * s, fill=hat_color, outline="")
    canvas.create_rectangle(x - 2 * s, head_y + 2 * s, x + 4 * s, head_y + 8 * s, fill=hat_color, outline="")
    # 帽子上的 M
    canvas.create_text(x + 12 * s, head_y + 3 * s, text="M", font=("", 7, "bold"), fill="#FFFFFF")

# ========================
# 主循环
# ========================
def game_loop():
    global game_over, game_won, lbl_msg_text

    if not game_running:
        return

    lbl_msg_text = ""

    if not game_over and not game_won:
        update_player()
        update_coins()
        update_enemies()
        update_mushrooms()
        update_particles()

        # 检查胜利（到达地图最右端）
        if player and player["x"] > map_width - 80:
            game_won = True

        # 检查时间
        elapsed = time.time() - start_time
        if elapsed > time_left:
            global lives
            lives = 0
            game_over = True

    draw()

    # 更新 HUD
    if lbl_score:
        lbl_score.config(text=f"🏆 {score}")
    if lbl_coins:
        lbl_coins.config(text=f"🪙 {coins_count}")
    if lbl_lives:
        lbl_lives.config(text=f"❤️ {lives}")

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

# ========================
# 输入
# ========================
lbl_msg_text = ""

def key_down(e):
    global game_over, game_won, lbl_msg_text
    keys = root.keys_pressed

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

    keys.add(e.keysym)

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

# ========================
# 重置
# ========================
def reset_game():
    global score, coins_count, lives, game_over, game_won, start_time, lbl_msg_text
    score = 0
    coins_count = 0
    lives = 3
    game_over = False
    game_won = False
    start_time = time.time()
    lbl_msg_text = ""
    build_level()
    create_player()

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

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

    root = tk.Tk()
    root.title("🍄 超级马里奥 · Python 版")
    root.resizable(False, False)
    root.keys_pressed = set()

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

    lbl_score = tk.Label(hud, text="🏆 0", font=("Comic Sans MS", 12, "bold"))
    lbl_score.pack(side="left", padx=10)

    lbl_coins = tk.Label(hud, text="🪙 0", font=("Comic Sans MS", 12))
    lbl_coins.pack(side="left", padx=10)

    lbl_lives = tk.Label(hud, text="❤️ 3", font=("Comic Sans MS", 12))
    lbl_lives.pack(side="left", padx=10)

    lbl_msg = tk.Label(hud, text="", font=("Comic Sans MS", 10), fg="#FF0000")
    lbl_msg.pack(side="left", padx=20)

    # 主题栏
    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), build_level()])
        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="A/D 或 ←/→ 移动 | W/Space/↑ 跳跃 | R 重开", font=("Comic Sans MS", 9)).pack()

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

# ========================
# 启动
# ========================
if __name__ == "__main__":
    build_ui()
    apply_theme("🍄 经典蘑菇")
    build_level()
    create_player()
    start_time = time.time()
    root.bind("<KeyPress>", key_down)
    root.bind("<KeyRelease>", key_up)
    root.after(100, game_loop)
    root.mainloop()
