import tkinter as tk
import random
import math
import time
from collections import deque

class Vector3:
    """简单的3D向量类"""
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z
    
    def __add__(self, other):
        return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
    
    def __sub__(self, other):
        return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
    
    def __mul__(self, scalar):
        return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)
    
    def length(self):
        return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
    
    def normalize(self):
        l = self.length()
        if l > 0:
            return Vector3(self.x/l, self.y/l, self.z/l)
        return Vector3()

class Player:
    """玩家类"""
    def __init__(self):
        self.position = Vector3(0, 1, 5)  # 玩家位置
        self.velocity = Vector3(0, 0, 0)  # 玩家速度
        self.jumping = False
        self.score = 0
        self.lives = 3
        self.size = 0.5
        self.speed = 0.1
        self.jump_power = 0.2
        self.gravity = 0.01
    
    def jump(self):
        if not self.jumping:
            self.velocity.y = self.jump_power
            self.jumping = True
    
    def update(self):
        # 应用重力
        self.velocity.y -= self.gravity
        
        # 更新位置
        self.position.x += self.velocity.x
        self.position.y += self.velocity.y
        self.position.z += self.velocity.z
        
        # 地面碰撞
        if self.position.y < 1:
            self.position.y = 1
            self.velocity.y = 0
            self.jumping = False
        
        # 限制左右移动范围
        if self.position.x < -4:
            self.position.x = -4
        if self.position.x > 4:
            self.position.x = 4

class Obstacle:
    """障碍物类"""
    def __init__(self, z):
        self.position = Vector3(random.uniform(-3, 3), 0.5, z)
        self.width = random.uniform(0.5, 1.5)
        self.height = random.uniform(0.5, 2.0)
        self.depth = 1.0
        self.color = f"#{random.randint(128, 255):02x}0000"  # 红色系
        self.passed = False
    
    def update(self, speed):
        self.position.z -= speed
        return self.position.z > -20  # 只保留可见的障碍物
    
    def get_screen_pos(self, player_pos, canvas_width, canvas_height):
        """将3D坐标转换为2D屏幕坐标"""
        # 相对位置
        dx = self.position.x - player_pos.x
        dy = self.position.y - player_pos.y
        dz = self.position.z - player_pos.z
        
        if dz <= 0.1:  # 避免除以0或负数
            return None
        
        # 简单的3D透视投影
        scale = 200 / dz
        screen_x = canvas_width/2 + dx * scale
        screen_y = canvas_height/2 - dy * scale
        
        # 计算屏幕上的大小
        screen_width = self.width * scale
        screen_height = self.height * scale
        
        return (screen_x, screen_y, screen_width, screen_height)

class Coin:
    """金币类"""
    def __init__(self, z):
        self.position = Vector3(random.uniform(-3, 3), 1.5, z)
        self.radius = 0.3
        self.collected = False
        self.spin = 0
    
    def update(self, speed):
        self.position.z -= speed
        self.spin += 5
        return self.position.z > -20 and not self.collected
    
    def get_screen_pos(self, player_pos, canvas_width, canvas_height):
        """将3D坐标转换为2D屏幕坐标"""
        dx = self.position.x - player_pos.x
        dy = self.position.y - player_pos.y
        dz = self.position.z - player_pos.z
        
        if dz <= 0.1:
            return None
        
        scale = 200 / dz
        screen_x = canvas_width/2 + dx * scale
        screen_y = canvas_height/2 - dy * scale
        screen_radius = self.radius * scale
        
        return (screen_x, screen_y, screen_radius)

class Road:
    """道路类"""
    def __init__(self, length=100, width=8):
        self.length = length
        self.width = width
        self.segments = []
        
        # 创建道路段
        for z in range(-5, length, 2):
            self.segments.append(z)
    
    def draw(self, canvas, player_pos, canvas_width, canvas_height):
        """绘制道路"""
        for z in self.segments:
            # 道路左右边界
            for x in [-self.width/2, self.width/2]:
                dx = x - player_pos.x
                dz = z - player_pos.z
                
                if dz <= 0.1:
                    continue
                
                scale = 200 / dz
                screen_x = canvas_width/2 + dx * scale
                screen_y = canvas_height/2 + 0.5 * scale
                
                # 绘制道路标记
                if z % 4 == 0:
                    canvas.create_oval(
                        screen_x-2, screen_y-2,
                        screen_x+2, screen_y+2,
                        fill="white", outline="white"
                    )

class ParkourGame:
    """主游戏类"""
    def __init__(self, root):
        self.root = root
        self.root.title("3D跑酷游戏 - Python内置版")
        self.root.geometry("1000x700")
        
        # 游戏状态
        self.game_over = False
        self.game_speed = 0.2
        self.score = 0
        self.level = 1
        
        # 创建游戏区域
        self.canvas = tk.Canvas(root, width=1000, height=700, bg="skyblue")
        self.canvas.pack()
        
        # 创建UI框架
        self.ui_frame = tk.Frame(root)
        self.ui_frame.pack(side=tk.TOP, fill=tk.X)
        
        # 分数标签
        self.score_label = tk.Label(self.ui_frame, text="分数: 0", font=("Arial", 16))
        self.score_label.pack(side=tk.LEFT, padx=20)
        
        # 生命标签
        self.lives_label = tk.Label(self.ui_frame, text="生命: 3", font=("Arial", 16))
        self.lives_label.pack(side=tk.LEFT, padx=20)
        
        # 等级标签
        self.level_label = tk.Label(self.ui_frame, text="等级: 1", font=("Arial", 16))
        self.level_label.pack(side=tk.LEFT, padx=20)
        
        # 速度标签
        self.speed_label = tk.Label(self.ui_frame, text="速度: 0.2", font=("Arial", 16))
        self.speed_label.pack(side=tk.LEFT, padx=20)
        
        # 重新开始按钮
        self.restart_button = tk.Button(
            self.ui_frame, text="重新开始", 
            command=self.restart_game, 
            font=("Arial", 12)
        )
        self.restart_button.pack(side=tk.RIGHT, padx=20)
        
        # 操作说明
        self.instructions = tk.Label(
            root, 
            text="操作: 左右箭头键移动, 空格键跳跃, P键暂停", 
            font=("Arial", 12)
        )
        self.instructions.pack()
        
        # 初始化游戏对象
        self.player = Player()
        self.road = Road()
        self.obstacles = []
        self.coins = []
        
        # 生成初始障碍物和金币
        self.generate_objects()
        
        # 绑定按键事件
        self.root.bind("<Left>", self.move_left)
        self.root.bind("<Right>", self.move_right)
        self.root.bind("<space>", self.jump)
        self.root.bind("<p>", self.toggle_pause)
        
        # 游戏循环
        self.paused = False
        self.last_time = time.time()
        self.game_loop()
    
    def generate_objects(self):
        """生成障碍物和金币"""
        for i in range(20):
            self.obstacles.append(Obstacle(random.uniform(10, 100)))
        
        for i in range(30):
            self.coins.append(Coin(random.uniform(10, 100)))
    
    def move_left(self, event):
        """向左移动"""
        if not self.game_over and not self.paused:
            self.player.velocity.x = -self.player.speed
    
    def move_right(self, event):
        """向右移动"""
        if not self.game_over and not self.paused:
            self.player.velocity.x = self.player.speed
    
    def jump(self, event):
        """跳跃"""
        if not self.game_over and not self.paused:
            self.player.jump()
    
    def toggle_pause(self, event):
        """暂停/继续游戏"""
        self.paused = not self.paused
    
    def restart_game(self):
        """重新开始游戏"""
        self.game_over = False
        self.game_speed = 0.2
        self.score = 0
        self.level = 1
        self.player = Player()
        self.obstacles = []
        self.coins = []
        self.generate_objects()
        self.update_ui()
    
    def update_ui(self):
        """更新UI显示"""
        self.score_label.config(text=f"分数: {self.player.score}")
        self.lives_label.config(text=f"生命: {self.player.lives}")
        self.level_label.config(text=f"等级: {self.level}")
        self.speed_label.config(text=f"速度: {self.game_speed:.1f}")
    
    def check_collisions(self):
        """检测碰撞"""
        # 检测障碍物碰撞
        for obstacle in self.obstacles:
            if not obstacle.passed:
                dx = abs(self.player.position.x - obstacle.position.x)
                dz = self.player.position.z - obstacle.position.z
                
                # 简单的碰撞检测
                if (dz > -1 and dz < 1 and 
                    dx < (self.player.size + obstacle.width/2) and
                    self.player.position.y < obstacle.height):
                    
                    self.player.lives -= 1
                    obstacle.passed = True
                    
                    if self.player.lives <= 0:
                        self.game_over = True
                        self.show_game_over()
        
        # 检测金币碰撞
        for coin in self.coins:
            if not coin.collected:
                dx = abs(self.player.position.x - coin.position.x)
                dz = self.player.position.z - coin.position.z
                dy = abs(self.player.position.y - coin.position.y)
                
                distance = math.sqrt(dx*dx + dz*dz + dy*dy)
                
                if distance < (self.player.size + coin.radius):
                    coin.collected = True
                    self.player.score += 10
                    
                    # 每100分升一级
                    new_level = self.player.score // 100 + 1
                    if new_level > self.level:
                        self.level = new_level
                        self.game_speed *= 1.2  # 每级加速20%
    
    def show_game_over(self):
        """显示游戏结束画面"""
        self.canvas.create_rectangle(
            300, 250, 700, 450,
            fill="black", stipple="gray50"
        )
        self.canvas.create_text(
            500, 300,
            text="游戏结束!",
            font=("Arial", 36, "bold"),
            fill="red"
        )
        self.canvas.create_text(
            500, 350,
            text=f"最终分数: {self.player.score}",
            font=("Arial", 24),
            fill="white"
        )
        self.canvas.create_text(
            500, 400,
            text="点击'重新开始'按钮重新开始游戏",
            font=("Arial", 16),
            fill="white"
        )
    
    def draw_objects(self):
        """绘制所有游戏对象"""
        # 清除画布
        self.canvas.delete("all")
        
        # 绘制天空
        self.canvas.create_rectangle(0, 0, 1000, 350, fill="skyblue", outline="")
        
        # 绘制地面
        self.canvas.create_rectangle(0, 350, 1000, 700, fill="saddle brown", outline="")
        
        # 绘制道路
        self.road.draw(self.canvas, self.player.position, 1000, 700)
        
        # 绘制障碍物
        for obstacle in self.obstacles:
            if obstacle.position.z > -20:  # 只绘制可见的障碍物
                pos = obstacle.get_screen_pos(self.player.position, 1000, 700)
                if pos:
                    x, y, w, h = pos
                    if 0 < x < 1000 and 0 < y < 700:
                        # 绘制3D效果障碍物
                        self.canvas.create_rectangle(
                            x - w/2, 700 - (y + h/2),
                            x + w/2, 700 - (y - h/2),
                            fill=obstacle.color, outline="black", width=2
                        )
        
        # 绘制金币
        for coin in self.coins:
            if not coin.collected and coin.position.z > -20:
                pos = coin.get_screen_pos(self.player.position, 1000, 700)
                if pos:
                    x, y, r = pos
                    if 0 < x < 1000 and 0 < y < 700:
                        # 绘制旋转的金币
                        self.canvas.create_oval(
                            x - r, 700 - (y + r),
                            x + r, 700 - (y - r),
                            fill="gold", outline="orange", width=2
                        )
        
        # 绘制玩家
        player_scale = 200 / (self.player.position.z + 5)
        player_x = 500
        player_y = 700 - (350 + 50 * player_scale)
        player_size = 20 * player_scale
        
        # 绘制玩家(三角形表示)
        points = [
            player_x, player_y - player_size,
            player_x - player_size, player_y + player_size,
            player_x + player_size, player_y + player_size
        ]
        self.canvas.create_polygon(points, fill="blue", outline="darkblue", width=2)
        
        # 如果游戏结束，显示游戏结束画面
        if self.game_over:
            self.show_game_over()
        
        # 如果暂停，显示暂停文本
        if self.paused:
            self.canvas.create_text(
                500, 100,
                text="游戏暂停",
                font=("Arial", 36, "bold"),
                fill="yellow"
            )
            self.canvas.create_text(
                500, 150,
                text="按P键继续",
                font=("Arial", 20),
                fill="white"
            )
    
    def game_loop(self):
        """游戏主循环"""
        if not self.paused and not self.game_over:
            current_time = time.time()
            delta_time = min(current_time - self.last_time, 0.05)  # 限制最大帧时间
            self.last_time = current_time
            
            # 更新玩家
            self.player.velocity.x *= 0.9  # 摩擦力
            self.player.update()
            
            # 更新障碍物
            self.obstacles = [obs for obs in self.obstacles if obs.update(self.game_speed)]
            
            # 补充新的障碍物
            while len(self.obstacles) < 20:
                self.obstacles.append(Obstacle(random.uniform(100, 150)))
            
            # 更新金币
            self.coins = [coin for coin in self.coins if coin.update(self.game_speed)]
            
            # 补充新的金币
            while len(self.coins) < 30:
                self.coins.append(Coin(random.uniform(100, 150)))
            
            # 检测碰撞
            self.check_collisions()
            
            # 更新UI
            self.update_ui()
        
        # 绘制所有对象
        self.draw_objects()
        
        # 继续游戏循环
        self.root.after(16, self.game_loop)  # 约60FPS

def main():
    """主函数"""
    root = tk.Tk()
    game = ParkourGame(root)
    root.mainloop()

if __name__ == "__main__":
    main()