import tkinter as tk
import random
import math

# ==================== 游戏常量 ====================
WIDTH, HEIGHT = 400, 600
FPS = 16  # ≈60FPS

GRAVITY = 0.4
JUMP_POWER = -12
MOVE_SPEED = 5
MAX_FALL_SPEED = 12

PLATFORM_WIDTH_MIN = 40
PLATFORM_WIDTH_MAX = 80
PLATFORM_GAP = 50  # 垂直间距

class Platform:
    def __init__(self, x, y, width, has_spike=False):
        self.x = x
        self.y = y
        self.width = width
        self.has_spike = has_spike
        self.id = None
        self.spike_id = None

    def draw(self, canvas):
        # 平台本体
        self.id = canvas.create_rectangle(
            self.x, self.y,
            self.x + self.width, self.y + 10,
            fill="#8B4513", outline="#654321", width=2
        )
        # 尖刺
        if self.has_spike:
            spike_width = self.width // 5
            self.spike_id = []
            for i in range(5):
                sx = self.x + i * spike_width
                spike = canvas.create_polygon(
                    sx, self.y,
                    sx + spike_width // 2, self.y - 12,
                    sx + spike_width, self.y,
                    fill="#FF4500", outline="#CC0000"
                )
                self.spike_id.append(spike)

    def move(self, dy):
        self.y += dy
        if self.id:
            self.canvas.move(self.id, 0, dy)
            if self.spike_id:
                for sid in self.spike_id:
                    self.canvas.move(sid, 0, dy)

    def is_off_screen(self):
        return self.y > HEIGHT

    def get_rect(self):
        return (self.x, self.y, self.x + self.width, self.y + 10)

    def destroy(self, canvas):
        canvas.delete(self.id)
        if self.spike_id:
            for sid in self.spike_id:
                canvas.delete(sid)


class Player:
    def __init__(self, canvas, x, y):
        self.canvas = canvas
        self.x = x
        self.y = y
        self.vx = 0
        self.vy = 0
        self.on_ground = False
        self.alive = True

        # 火柴人造型
        self.body_id = None
        self.head_id = None
        self.draw()

    def draw(self):
        # 头
        self.head_id = self.canvas.create_oval(
            self.x - 8, self.y - 25,
            self.x + 8, self.y - 9,
            fill="#FFDBAC", outline="#8B4513", width=1
        )
        # 身体
        self.body_id = self.canvas.create_line(
            self.x, self.y - 9,
            self.x, self.y + 5,
            fill="#3366CC", width=3
        )
        # 腿
        self.leg1 = self.canvas.create_line(
            self.x, self.y + 5,
            self.x - 5, self.y + 15,
            fill="#3366CC", width=2
        )
        self.leg2 = self.canvas.create_line(
            self.x, self.y + 5,
            self.x + 5, self.y + 15,
            fill="#3366CC", width=2
        )

    def update(self, platforms):
        if not self.alive:
            return

        # 水平移动
        self.x += self.vx

        # 边界限制（穿墙模式：从左边出去从右边进来）
        if self.x < 0:
            self.x = WIDTH
        elif self.x > WIDTH:
            self.x = 0

        # 重力
        self.vy += GRAVITY
        if self.vy > MAX_FALL_SPEED:
            self.vy = MAX_FALL_SPEED

        self.y += self.vy
        self.on_ground = False

        # 与平台碰撞检测
        player_rect = (self.x - 8, self.y - 25, self.x + 8, self.y + 15)

        for platform in platforms:
            px, py, px2, py2 = platform.get_rect()

            # 只在下落时检测
            if self.vy > 0 and self.y - 5 < py and self.y + 15 > py:
                if self.x + 5 > px and self.x - 5 < px2:
                    # 踩到平台
                    self.y = py - 15
                    self.vy = JUMP_POWER
                    self.on_ground = True

                    # 检测尖刺
                    if platform.has_spike:
                        self.alive = False
                    break

        # 掉出屏幕
        if self.y > HEIGHT + 50:
            self.alive = False

        # 更新画面位置
        self.canvas.coords(
            self.head_id,
            self.x - 8, self.y - 25,
            self.x + 8, self.y - 9
        )
        self.canvas.coords(
            self.body_id,
            self.x, self.y - 9,
            self.x, self.y + 5
        )
        self.canvas.coords(
            self.leg1,
            self.x, self.y + 5,
            self.x - 5, self.y + 15
        )
        self.canvas.coords(
            self.leg2,
            self.x, self.y + 5,
            self.x + 5, self.y + 15
        )

    def jump(self):
        if self.on_ground:
            self.vy = JUMP_POWER

    def move_left(self):
        self.vx = -MOVE_SPEED

    def move_right(self):
        self.vx = MOVE_SPEED

    def stop(self):
        self.vx = 0

    def destroy(self):
        self.canvas.delete(self.head_id)
        self.canvas.delete(self.body_id)
        self.canvas.delete(self.leg1)
        self.canvas.delete(self.leg2)


class Game:
    def __init__(self, root):
        self.root = root
        self.root.title("025. 是男人就上一百层")
        self.root.resizable(False, False)

        self.canvas = tk.Canvas(
            root, width=WIDTH, height=HEIGHT, bg="#87CEEB"
        )
        self.canvas.pack()

        self.platforms = []
        self.player = None
        self.score = 0
        self.high_score = 0
        self.game_state = "waiting"  # waiting / playing / gameover
        self.scroll_offset = 0
        self.difficulty = 1

        # UI
        self.score_text = self.canvas.create_text(
            10, 10, anchor="nw",
            text="层数: 0",
            fill="#333", font=("微软雅黑", 14, "bold")
        )
        self.hint_text = self.canvas.create_text(
            WIDTH // 2, HEIGHT // 2,
            text="是男人就上一百层！\n\n← → 移动\n空格键开始",
            fill="#333", font=("微软雅黑", 16, "bold"),
            justify=tk.CENTER
        )

        # 背景装饰
        self.draw_background()

        # 按键绑定
        self.root.bind("<Left>", lambda e: self.on_key_down("left"))
        self.root.bind("<Right>", lambda e: self.on_key_down("right"))
        self.root.bind("<space>", lambda e: self.on_space())
        self.root.bind("<KeyRelease>", self.on_key_up)

        self.keys_pressed = set()

    def draw_background(self):
        # 云朵
        for _ in range(4):
            x = random.randint(0, WIDTH)
            y = random.randint(50, 300)
            self.canvas.create_oval(
                x, y, x + 60, y + 30,
                fill="white", outline="", stipple="gray25"
            )

        # 地面
        self.canvas.create_rectangle(
            0, HEIGHT - 20, WIDTH, HEIGHT,
            fill="#8B4513", outline=""
        )
        self.canvas.create_rectangle(
            0, HEIGHT - 20, WIDTH, HEIGHT - 18,
            fill="#228B22", outline=""
        )

    def init_platforms(self):
        """初始化平台"""
        self.platforms.clear()

        # 第一层平台（起点）
        p = Platform(WIDTH // 2 - 30, HEIGHT - 60, 60, False)
        p.canvas = self.canvas
        p.draw(self.canvas)
        self.platforms.append(p)

        # 生成初始平台
        for i in range(1, 15):
            y = HEIGHT - 60 - i * PLATFORM_GAP
            x = random.randint(10, WIDTH - PLATFORM_WIDTH_MAX - 10)
            width = random.randint(PLATFORM_WIDTH_MIN, PLATFORM_WIDTH_MAX)
            has_spike = random.random() < 0.2
            p = Platform(x, y, width, has_spike)
            p.canvas = self.canvas
            p.draw(self.canvas)
            self.platforms.append(p)

    def start_game(self):
        self.canvas.delete("all")
        self.draw_background()

        self.score = 0
        self.game_state = "playing"
        self.scroll_offset = 0
        self.difficulty = 1

        self.score_text = self.canvas.create_text(
            10, 10, anchor="nw",
            text="层数: 0",
            fill="#333", font=("微软雅黑", 14, "bold")
        )

        self.init_platforms()
        self.player = Player(self.canvas, WIDTH // 2, HEIGHT - 80)
        self.game_loop()

    def on_key_down(self, key):
        if self.game_state != "playing":
            return
        self.keys_pressed.add(key)
        if key == "left":
            self.player.move_left()
        elif key == "right":
            self.player.move_right()

    def on_key_up(self, e):
        if e.keysym == "Left" and "left" in self.keys_pressed:
            self.keys_pressed.discard("left")
            if "right" not in self.keys_pressed:
                self.player.stop()
        elif e.keysym == "Right" and "right" in self.keys_pressed:
            self.keys_pressed.discard("right")
            if "left" not in self.keys_pressed:
                self.player.stop()

    def on_space(self):
        if self.game_state == "waiting" or self.game_state == "gameover":
            self.start_game()

    def game_loop(self):
        if self.game_state != "playing":
            return

        # 更新玩家
        self.player.update(self.platforms)

        if not self.player.alive:
            self.game_over()
            return

        # 计算滚动
        highest_y = min(p.y for p in self.platforms)
        target_scroll = 0

        if self.player.y < HEIGHT // 3:
            scroll_speed = 2 + self.difficulty * 0.5
            self.scroll_offset += scroll_speed

            # 移动所有平台
            for p in self.platforms:
                p.move(scroll_speed)

            # 玩家跟着移动
            self.player.y += scroll_speed
            self.player.canvas.coords(
                self.player.head_id,
                self.player.x - 8, self.player.y - 25,
                self.player.x + 8, self.player.y - 9
            )
            self.player.canvas.coords(
                self.player.body_id,
                self.player.x, self.player.y - 9,
                self.player.x, self.player.y + 5
            )
            self.player.canvas.coords(
                self.player.leg1,
                self.player.x, self.player.y + 5,
                self.player.x - 5, self.player.y + 15
            )
            self.player.canvas.coords(
                self.player.leg2,
                self.player.x, self.player.y + 5,
                self.player.x + 5, self.player.y + 15
            )

        # 移除屏幕外的平台
        for p in self.platforms[:]:
            if p.is_off_screen():
                p.destroy(self.canvas)
                self.platforms.remove(p)
                self.score += 1

                # 难度递增
                if self.score % 10 == 0:
                    self.difficulty += 1

        # 补充新平台
        while len(self.platforms) < 15:
            max_y = max(p.y for p in self.platforms)
            y = max_y - PLATFORM_GAP
            x = random.randint(10, WIDTH - PLATFORM_WIDTH_MAX - 10)
            width = random.randint(PLATFORM_WIDTH_MIN, PLATFORM_WIDTH_MAX)
            has_spike = random.random() < min(0.15 + self.difficulty * 0.05, 0.5)
            p = Platform(x, y, width, has_spike)
            p.canvas = self.canvas
            p.draw(self.canvas)
            self.platforms.append(p)

        # 更新分数显示
        self.canvas.itemconfig(
            self.score_text,
            text=f"层数: {self.score}"
        )

        self.root.after(FPS, self.game_loop)

    def game_over(self):
        self.game_state = "gameover"
        self.high_score = max(self.high_score, self.score)

        # 半透明遮罩
        self.canvas.create_rectangle(
            0, 0, WIDTH, HEIGHT,
            fill="black", stipple="gray50", tags="overlay"
        )
        self.canvas.create_text(
            WIDTH // 2, HEIGHT // 2 - 40,
            text="游戏结束！",
            fill="#FF4500", font=("微软雅黑", 28, "bold"),
            tags="overlay"
        )
        self.canvas.create_text(
            WIDTH // 2, HEIGHT // 2 + 10,
            text=f"到达层数: {self.score}",
            fill="white", font=("微软雅黑", 16),
            tags="overlay"
        )
        self.canvas.create_text(
            WIDTH // 2, HEIGHT // 2 + 45,
            text=f"最高纪录: {self.high_score}",
            fill="#FFD700", font=("微软雅黑", 14),
            tags="overlay"
        )
        self.canvas.create_text(
            WIDTH // 2, HEIGHT // 2 + 90,
            text="按空格键重新开始",
            fill="#AAAAAA", font=("微软雅黑", 12),
            tags="overlay"
        )


if __name__ == "__main__":
    root = tk.Tk()
    game = Game(root)
    root.mainloop()