import tkinter as tk
import math
import random

# ========================
# 全局配置
# ========================
WIDTH, HEIGHT = 900, 600
FPS = 60
GROUND_Y = HEIGHT - 150

# ========================
# 游戏状态（✅ 全部提前定义）
# ========================
player_x = 200        # 玩家在地图上的真实坐标
camera_x = 0          # 摄像机偏移
player_y = GROUND_Y
is_charging = False
charge_time = 0
max_charge = 800

jumping = False
jump_progress = 0
jump_start_x = 0
jump_start_y = 0
jump_distance = 0
target_x = 0

score = 0
combo = 0
best_score = 0
game_over = False

blocks = []          # 所有方块（地图坐标）
particles = []
floating_texts = []

current_theme = "🎨 经典"

# ========================
# Tkinter 窗口
# ========================
root = tk.Tk()
root.title("🎮 跳一跳 · 超长地图版")
root.resizable(False, False)

canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, highlightthickness=0)
canvas.pack()

panel = tk.Frame(root)
panel.pack(fill="x")

info = tk.Label(panel, font=("Consolas", 10))
info.pack(side="left", padx=10)

# ========================
# 主题（✅ 无半透明）
# ========================
themes = {
    "🎨 经典": {"bg": "#F5F5F5", "block": "#FFFFFF", "player": "#333333", "shadow": "#CCCCCC", "ground": "#E0E0E0"},
    "🌌 星空": {"bg": "#0D1B2A", "block": "#1B263B", "player": "#00FFFF", "shadow": "#415A77", "ground": "#0A1128"},
    "🌲 森林": {"bg": "#E8F5E9", "block": "#C8E6C9", "player": "#FF6B6B", "shadow": "#A5D6A7", "ground": "#A5D6A7"},
    "🌃 霓虹": {"bg": "#1A1A2E", "block": "#16213E", "player": "#FF2E63", "shadow": "#0F3460", "ground": "#0F3460"},
    "🍬 糖果": {"bg": "#FCE4EC", "block": "#F8BBD0", "player": "#BA68C8", "shadow": "#F48FB1", "ground": "#F8BBD0"},
    "⬜ 极简": {"bg": "#FFFFFF", "block": "#EEEEEE", "player": "#000000", "shadow": "#DDDDDD", "ground": "#F5F5F5"},
}

def apply_theme(name):
    global current_theme
    current_theme = name
    t = themes[name]
    root.configure(bg=t["bg"])
    panel.configure(bg=t["bg"])
    info.configure(bg=t["bg"], fg="#000000" if name == "🎨 经典" else "#FFFFFF")
    canvas.configure(background=t["bg"])

# ========================
# 方块生成（✅ 无限地图）
# ========================
def generate_initial_blocks():
    """初始生成30个方块"""
    global blocks
    blocks.clear()
    x = 100
    for i in range(30):
        w = random.randint(60, 100)
        h = random.randint(30, 50)
        kind = "normal"
        if i > 3:
            r = random.random()
            if r < 0.1: kind = "music"
            elif r < 0.2: kind = "shop"
            elif r < 0.3: kind = "cube"
            elif r < 0.4: kind = "manhole"
            elif r < 0.5: kind = "clock"
        blocks.append({"x": x, "y": GROUND_Y, "w": w, "h": h, "kind": kind})
        x += random.randint(150, 350)

def ensure_blocks_ahead():
    """确保玩家前方始终有足够方块"""
    if not blocks:
        return
    last_x = blocks[-1]["x"] + blocks[-1]["w"]
    while last_x < player_x + WIDTH * 2:
        w = random.randint(60, 100)
        h = random.randint(30, 50)
        r = random.random()
        if r < 0.1: kind = "music"
        elif r < 0.2: kind = "shop"
        elif r < 0.3: kind = "cube"
        elif r < 0.4: kind = "manhole"
        elif r < 0.5: kind = "clock"
        else: kind = "normal"
        blocks.append({"x": last_x + random.randint(150, 350), "y": GROUND_Y, "w": w, "h": h, "kind": kind})
        last_x += w

def cleanup_blocks_behind():
    """删除身后太远的方块，节省内存"""
    global blocks
    threshold = player_x - WIDTH
    blocks = [b for b in blocks if b["x"] + b["w"] > threshold]

# ========================
# 摄像机
# ========================
def update_camera():
    """摄像机平滑跟随玩家，玩家始终在屏幕左1/3处"""
    global camera_x
    target_cam = player_x - WIDTH // 3
    camera_x += (target_cam - camera_x) * 0.1
    if camera_x < 0:
        camera_x = 0

def world_to_screen(wx):
    """世界坐标 → 屏幕坐标"""
    return wx - camera_x

# ========================
# 绘制地面（无限延伸感）
# ========================
def draw_ground():
    canvas.delete("ground")
    t = themes[current_theme]
    # 地面填充
    canvas.create_rectangle(0, GROUND_Y + 50, WIDTH, HEIGHT, fill=t["ground"], outline="", tags="ground")
    # 地面线
    canvas.create_line(0, GROUND_Y + 50, WIDTH, GROUND_Y + 50, fill="#BBBBBB", width=2, tags="ground")
    # 远处装饰线（透视感）
    for i in range(5):
        y = GROUND_Y + 50 + i * 20
        alpha = 200 - i * 30
        c = f"#{alpha:02x}{alpha:02x}{alpha:02x}"
        canvas.create_line(0, y, WIDTH, y, fill=c, tags="ground")

# ========================
# 绘制方块
# ========================
def draw_blocks():
    canvas.delete("block")
    t = themes[current_theme]
    for b in blocks:
        sx = world_to_screen(b["x"])
        # 只画屏幕内的
        if sx + b["w"] < 0 or sx > WIDTH:
            continue
        # 阴影
        canvas.create_rectangle(sx+5, b["y"]+5, sx+b["w"]+5, b["y"]+b["h"]+5, fill="#CCCCCC", outline="", tags="block")
        # 主体
        canvas.create_rectangle(sx, b["y"], sx+b["w"], b["y"]+b["h"], fill=t["block"], outline="#BBBBBB", width=2, tags="block")
        # 高光
        canvas.create_rectangle(sx+5, b["y"]+5, sx+b["w"]-5, b["y"]+15, fill="#F5F5F5", outline="", tags="block")
        # 图标
        icons = {"music": "♪", "shop": "🏪", "cube": "⬛", "manhole": "⊙", "clock": "🕐"}
        if b["kind"] in icons:
            canvas.create_text(sx+b["w"]//2, b["y"]+b["h"]//2, text=icons[b["kind"]], fill="#666666", font=("", 16), tags="block")

# ========================
# 绘制玩家
# ========================
def draw_player():
    canvas.delete("player")
    t = themes[current_theme]
    px = world_to_screen(player_x)
    py = player_y
    
    # 阴影
    canvas.create_oval(px-25, py+40, px+25, py+55, fill="#CCCCCC", outline="", tags="player")
    # 身体
    canvas.create_oval(px-20, py-40*squash, px+20, py+40*squash, fill=t["player"], outline="#000000", width=2, tags="player")
    # 眼睛
    canvas.create_oval(px-6, py-15, px-2, py-10, fill="#FFFFFF", outline="", tags="player")
    canvas.create_oval(px+2, py-15, px+6, py-10, fill="#FFFFFF", outline="", tags="player")

# ========================
# 蓄力条
# ========================
def draw_charge_bar():
    canvas.delete("charge")
    if not is_charging: return
    progress = min(charge_time / max_charge, 1.0)
    bw = 200
    canvas.create_rectangle(WIDTH//2-bw//2, 50, WIDTH//2+bw//2, 70, outline="#000000", width=2, tags="charge")
    color = "#00FF00" if progress < 0.5 else "#FFFF00" if progress < 0.8 else "#FF0000"
    canvas.create_rectangle(WIDTH//2-bw//2, 50, WIDTH//2-bw//2+bw*progress, 70, fill=color, outline="", tags="charge")
    canvas.create_text(WIDTH//2, 40, text=f"蓄力: {int(progress*100)}%", fill="#000000", font=("Consolas", 10), tags="charge")

# ========================
# 粒子
# ========================
def draw_particles():
    canvas.delete("particle")
    for p in particles[:]:
        canvas.create_oval(p["x"]-3, p["y"]-3, p["x"]+3, p["y"]+3, fill=p["color"], outline="", tags="particle")
        p["x"] += p["vx"]; p["y"] += p["vy"]; p["life"] -= 1
        if p["life"] <= 0: particles.remove(p)

def draw_floating_texts():
    canvas.delete("float")
    for ft in floating_texts[:]:
        canvas.create_text(ft["x"], ft["y"], text=ft["text"], fill=ft["color"], font=("Consolas", 12, "bold"), tags="float")
        ft["y"] -= 1; ft["life"] -= 1
        if ft["life"] <= 0: floating_texts.remove(ft)

# ========================
# UI
# ========================
def draw_ui():
    canvas.delete("ui")
    canvas.create_text(20, 20, anchor="nw", text=f"得分: {score}  连击: {combo}  最高: {best_score}", fill="#000000", font=("Consolas", 12), tags="ui")
    canvas.create_text(WIDTH-20, 20, anchor="ne", text=f"距离: {int(player_x)}m", fill="#666666", font=("Consolas", 10), tags="ui")
    if game_over:
        canvas.create_text(WIDTH//2, HEIGHT//2, text="💥 GAME OVER\n按 R 重开", fill="#FF0000", font=("Consolas", 28, "bold"), tags="ui")

# ========================
# 场景绘制
# ========================
def draw_scene():
    draw_ground()
    draw_blocks()
    draw_player()
    draw_particles()
    draw_floating_texts()
    draw_charge_bar()
    draw_ui()

# ========================
# 游戏逻辑
# ========================
def add_particles(x, y, color, count=10):
    for _ in range(count):
        particles.append({"x": world_to_screen(x), "y": y, "vx": random.uniform(-3,3), "vy": random.uniform(-5,-1), "color": color, "life": 30})

def add_floating_text(x, y, text, color="#FFD700"):
    floating_texts.append({"x": world_to_screen(x), "y": y, "text": text, "color": color, "life": 60})

def start_jump():
    global jumping, jump_progress, jump_start_x, jump_start_y, jump_distance, target_x, is_charging, charge_time
    if jumping or game_over: return
    
    jump_distance = (charge_time / max_charge) * 500 + 50
    jump_distance = min(jump_distance, 600)
    
    # 找目标方块
    target_block = None
    for b in blocks:
        if b["x"] > player_x and b["x"] - player_x < jump_distance + 80:
            target_block = b
            break
    
    if target_block:
        target_x = target_block["x"] + target_block["w"] // 2
    else:
        target_x = player_x + jump_distance
    
    jumping = True
    jump_progress = 0
    jump_start_x = player_x
    jump_start_y = player_y
    is_charging = False
    charge_time = 0
    add_particles(player_x, player_y + 40, "#CCCCCC", 5)

def update_jump():
    global jumping, jump_progress, player_x, player_y, score, combo, game_over
    if not jumping: return
    
    jump_progress += 0.02
    if jump_progress > 1:
        jumping = False
        check_landing()
        return
    
    t = jump_progress
    player_x = jump_start_x + (target_x - jump_start_x) * t
    peak = 40 + jump_distance * 0.15
    player_y = jump_start_y - 4 * peak * t * (1 - t)

def check_landing():
    global score, combo, game_over, player_y
    landed = False
    for b in blocks:
        if b["x"] <= player_x <= b["x"] + b["w"]:
            player_y = b["y"] - 40
            landed = True
            center = b["x"] + b["w"] // 2
            if abs(player_x - center) < 10:
                combo = min(combo + 2, 32)
                score += combo
                add_floating_text(player_x, player_y - 60, f"+{combo} 完美!", "#FFD700")
            else:
                combo = 0
                score += 1
                add_floating_text(player_x, player_y - 60, "+1", "#FFFFFF")
            # 特殊方块
            bonuses = {"music": (30,"音乐盒!","#FF6B6B"), "shop": (15,"便利店!","#4CAF50"),
                       "cube": (10,"魔方!","#2196F3"), "manhole": (5,"井盖!","#8BC34A"), "clock": (8,"时钟!","#FFC107")}
            if b["kind"] in bonuses:
                val, txt, col = bonuses[b["kind"]]
                score += val
                add_floating_text(player_x, player_y - 80, f"+{val} {txt}", col)
            add_particles(player_x, player_y + 40, "#FFD700", 15)
            break
    
    if not landed:
        game_over = True
        add_particles(player_x, GROUND_Y, "#FF0000", 30)
        global best_score
        if score > best_score: best_score = score

# ========================
# 游戏循环
# ========================
def game_loop():
    global squash
    if not game_over:
        if is_charging:
            global charge_time
            charge_time += 16
            if charge_time > max_charge: charge_time = max_charge
        update_jump()
        update_camera()
        ensure_blocks_ahead()
        cleanup_blocks_behind()
    
    squash = 1.2 if is_charging else (0.9 if jumping else 1.0)
    draw_scene()
    root.after(int(1000 / FPS), game_loop)

# ========================
# 键盘控制
# ========================
def key_down(e):
    global is_charging, game_over
    if game_over:
        if e.keysym == "r": restart_game()
        return
    if e.keysym in ("space", "w", "Up", "j"):
        is_charging = True

def key_up(e):
    global is_charging
    if e.keysym in ("space", "w", "Up", "j"):
        if is_charging:
            start_jump()
        is_charging = False

def restart_game():
    global score, combo, game_over, player_x, player_y, charge_time, is_charging, jumping, particles, floating_texts, camera_x
    score = combo = 0
    game_over = False
    player_x = 200
    player_y = GROUND_Y
    charge_time = 0
    is_charging = False
    jumping = False
    camera_x = 0
    particles.clear()
    floating_texts.clear()
    generate_initial_blocks()

root.bind("<KeyPress>", key_down)
root.bind("<KeyRelease>", key_up)

# ========================
# 换肤按钮
# ========================
for name in themes:
    tk.Button(panel, text=name, command=lambda n=name: apply_theme(n)).pack(side="right", padx=2)

# ========================
# 启动
# ========================
apply_theme("🎨 经典")
generate_initial_blocks()
game_loop()
root.mainloop()