import tkinter as tk
import random

# 游戏常量
WIDTH = 800
HEIGHT = 400
GRAVITY = 1.2
JUMP_FORCE = -22
PLAYER_NORMAL_HEIGHT = 40
PLAYER_CROUCH_HEIGHT = 22  # 下蹲缩小身高
PLAYER_WIDTH = 40
OBSTACLE_WIDTH = 30
OBSTACLE_HEIGHT = 50
GROUND_Y = HEIGHT - 60

class ParkourGame:
    def __init__(self, root):
        self.root = root
        self.root.title("Tkinter跑酷-二段跳+下蹲闪避")
        self.canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="#87CEEB")
        self.canvas.pack()

        # 玩家基础坐标
        self.player_x = 80
        self.player_y = GROUND_Y - PLAYER_NORMAL_HEIGHT
        self.vel_y = 0
        self.is_jump = False
        self.jump_count = 0  # 跳跃计数，实现二段跳
        self.max_jump = 2
        self.is_crouch = False  # 是否下蹲

        # 障碍物与分数
        self.obstacles = []
        self.obstacle_speed = 6
        self.score = 0
        self.game_over = False

        # 地面绘制
        self.ground = self.canvas.create_rectangle(0, GROUND_Y, WIDTH, HEIGHT, fill="#8B4513")
        # 玩家矩形（初始站立）
        self.player = self.canvas.create_rectangle(
            self.player_x, self.player_y,
            self.player_x + PLAYER_WIDTH, self.player_y + PLAYER_NORMAL_HEIGHT,
            fill="#FF4500"
        )
        # UI文本
        self.score_text = self.canvas.create_text(60, 30, text=f"分数: {self.score}", font=("微软雅黑", 16), fill="black")
        self.tip_text = self.canvas.create_text(WIDTH//2, 20, text="空格跳跃(可二段跳) | 下键下蹲闪避", font=("微软雅黑",12), fill="darkblue")
        self.game_over_text = self.canvas.create_text(WIDTH//2, HEIGHT//2, text="", font=("微软雅黑", 30), fill="red")

        # 按键绑定
        self.root.bind("<space>", self.jump)
        self.root.bind("<Down>", self.start_crouch)
        self.root.bind("<KeyRelease-Down>", self.end_crouch)

        self.spawn_obstacle()
        self.game_loop()

    def jump(self, event):
        """二段跳逻辑：落地重置跳跃次数，空中最多跳两次，下蹲时不能跳"""
        if self.game_over or self.is_crouch:
            return
        if self.jump_count < self.max_jump:
            self.vel_y = JUMP_FORCE
            self.jump_count += 1
            self.is_jump = True

    def start_crouch(self, event):
        """按下下键下蹲，降低碰撞高度，空中也能蹲"""
        if self.game_over or self.is_crouch:
            return
        self.is_crouch = True
        # 下蹲后角色底部贴地，高度压缩
        self.player_y = GROUND_Y - PLAYER_CROUCH_HEIGHT
        self.refresh_player_rect()

    def end_crouch(self, event):
        """松开下键起身恢复站立"""
        if self.game_over or not self.is_crouch:
            return
        self.is_crouch = False
        self.player_y = GROUND_Y - PLAYER_NORMAL_HEIGHT
        self.refresh_player_rect()

    def refresh_player_rect(self):
        """刷新玩家矩形尺寸坐标"""
        h = PLAYER_CROUCH_HEIGHT if self.is_crouch else PLAYER_NORMAL_HEIGHT
        self.canvas.coords(
            self.player,
            self.player_x, self.player_y,
            self.player_x + PLAYER_WIDTH, self.player_y + h
        )

    def spawn_obstacle(self):
        if self.game_over:
            return
        x = WIDTH
        y = GROUND_Y - OBSTACLE_HEIGHT
        obs = self.canvas.create_rectangle(x, y, x+OBSTACLE_WIDTH, y+OBSTACLE_HEIGHT, fill="#2F4F4F")
        self.obstacles.append(obs)
        delay = random.randint(800, 1500)
        self.root.after(delay, self.spawn_obstacle)

    def update_physics(self):
        """重力、落地判定，落地清空二段跳次数"""
        self.vel_y += GRAVITY
        self.player_y += self.vel_y

        current_h = PLAYER_CROUCH_HEIGHT if self.is_crouch else PLAYER_NORMAL_HEIGHT
        floor_pos = GROUND_Y - current_h

        # 落地锁定
        if self.player_y >= floor_pos:
            self.player_y = floor_pos
            self.vel_y = 0
            self.is_jump = False
            self.jump_count = 0  # 落地重置二段跳
        self.refresh_player_rect()

    def move_obstacles(self):
        to_del = []
        for obs in self.obstacles:
            x1, y1, x2, y2 = self.canvas.coords(obs)
            self.canvas.move(obs, -self.obstacle_speed, 0)
            if x2 < 0:
                to_del.append(obs)
                self.score += 1
                self.canvas.itemconfig(self.score_text, text=f"分数: {self.score}")
        for o in to_del:
            self.obstacles.remove(o)
            self.canvas.delete(o)

    def check_collision(self):
        """下蹲体型更小，更容易躲过矮障碍"""
        px1, py1, px2, py2 = self.canvas.coords(self.player)
        for obs in self.obstacles:
            ox1, oy1, ox2, oy2 = self.canvas.coords(obs)
            if px2 > ox1 and px1 < ox2 and py2 > oy1 and py1 < oy2:
                self.game_over = True
                self.canvas.itemconfig(self.game_over_text, text=f"游戏结束！得分:{self.score}\n空格重新开始")

    def reset_game(self):
        self.game_over = False
        self.score = 0
        self.obstacle_speed = 6
        self.jump_count = 0
        self.is_crouch = False
        self.vel_y = 0
        self.canvas.itemconfig(self.score_text, text=f"分数: {self.score}")
        self.canvas.itemconfig(self.game_over_text, text="")
        # 清空障碍物
        for o in self.obstacles:
            self.canvas.delete(o)
        self.obstacles.clear()
        # 玩家复位站立
        self.player_y = GROUND_Y - PLAYER_NORMAL_HEIGHT
        self.refresh_player_rect()
        self.spawn_obstacle()

    def game_loop(self):
        if self.game_over:
            self.root.bind("<space>", lambda e: self.reset_game())
        else:
            self.update_physics()
            self.move_obstacles()
            self.check_collision()
            # 分数越高速度越快
            if self.score % 10 == 0 and self.obstacle_speed < 12:
                self.obstacle_speed += 0.1
        self.root.after(20, self.game_loop)

if __name__ == "__main__":
    win = tk.Tk()
    game = ParkourGame(win)
    win.mainloop()