import tkinter as tk
from tkinter import ttk, messagebox
import random
import time
import os

# 窗口与画布尺寸
WINDOW_W = 800
WINDOW_H = 600
UI_HEIGHT = 56

# 赛道与对象尺寸
TRACK_MARGIN = 40
CAR_SIZE = 36
OBSTACLE_SIZE = 26
OBSTACLE_COUNT = 8
MAX_LIFE = 3

# 颜色
BG_COLOR = "#8fd18f"
ROAD_COLOR = "#2f2f2f"
LINE_COLOR = "#ffffff"
CAR_COLOR = "#101010"
OBST_COLOR = "#c62828"
FINISH_COLOR = "#ffd54f"

class Car:
    def __init__(self, x, y, size=CAR_SIZE):
        self.x = x
        self.y = y
        self.vx = 0.0
        self.vy = 0.0
        self.size = size
        self.max_speed = 6.0

    def rect(self):
        s = self.size
        return (self.x - s/2, self.y - s/2, self.x + s/2, self.y + s/2)

class Obstacle:
    def __init__(self, x, y, size=OBSTACLE_SIZE):
        self.x = x
        self.y = y
        self.size = size

    def rect(self):
        s = self.size
        return (self.x - s/2, self.y - s/2, self.x + s/2, self.y + s/2)

class GameApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("罗小黑 2D 赛车")
        self.resizable(False, False)
        self.geometry(f"{WINDOW_W}x{WINDOW_H}")

        # 游戏状态变量（必须预先初始化，避免后续 getattr 转发问题）
        self.running = False
        self.paused = False
        self.start_time = None
        self.elapsed = 0.0
        self.score = 0
        self.life = MAX_LIFE
        self.after_id = None  # 存放 after 返回的 id，便于取消

        # 赛道范围
        self.track_x0 = TRACK_MARGIN
        self.track_y0 = TRACK_MARGIN
        self.track_x1 = WINDOW_W - TRACK_MARGIN
        self.track_y1 = WINDOW_H - TRACK_MARGIN - UI_HEIGHT + 10

        # 创建车、障碍
        start_x = (self.track_x0 + self.track_x1) / 2
        start_y = self.track_y1 - 60
        self.car = Car(start_x, start_y)
        self.obstacles = []

        # 键盘状态
        self.keys = {}

        # UI
        self.create_widgets()
        self.bind_events()

        # 生成初始关卡
        self.reset_game()

    def create_widgets(self):
        top = ttk.Frame(self, padding=6)
        top.pack(side="top", fill="x")

        self.start_btn = ttk.Button(top, text="开始", command=self.start_game)
        self.start_btn.pack(side="left", padx=4)
        self.pause_btn = ttk.Button(top, text="暂停", command=self.toggle_pause)
        self.pause_btn.pack(side="left", padx=4)
        ttk.Button(top, text="重置", command=self.reset_game).pack(side="left", padx=4)

        ttk.Label(top, text="生命：").pack(side="left", padx=(12,2))
        self.life_var = tk.StringVar(value=str(self.life))
        ttk.Label(top, textvariable=self.life_var).pack(side="left")

        ttk.Label(top, text="   得分：").pack(side="left", padx=(12,2))
        self.score_var = tk.StringVar(value=str(self.score))
        ttk.Label(top, textvariable=self.score_var).pack(side="left")

        ttk.Label(top, text="   用时：").pack(side="left", padx=(12,2))
        self.time_var = tk.StringVar(value="0.0")
        ttk.Label(top, textvariable=self.time_var).pack(side="left")

        # 画布（留出顶部 UI 高度）
        self.canvas = tk.Canvas(self, width=WINDOW_W, height=WINDOW_H-UI_HEIGHT, bg=BG_COLOR)
        self.canvas.pack(padx=4, pady=0)

    def bind_events(self):
        self.bind_all("<KeyPress>", self.on_key_press)
        self.bind_all("<KeyRelease>", self.on_key_release)

    def on_key_press(self, event):
        k = event.keysym
        # 支持箭头与 WASD
        if k in ("Up","Down","Left","Right","w","a","s","d"):
            self.keys[k] = True

    def on_key_release(self, event):
        k = event.keysym
        if k in self.keys:
            self.keys[k] = False

    def start_game(self):
        if not self.running:
            self.running = True
            self.paused = False
            self.start_time = time.time() - self.elapsed
            # 启动循环
            if self.after_id is None:
                self.after_id = self.after(16, self.game_loop)

    def toggle_pause(self):
        if not self.running:
            return
        self.paused = not self.paused
        if not self.paused:
            # 恢复计时基准
            self.start_time = time.time() - self.elapsed
            if self.after_id is None:
                self.after_id = self.after(16, self.game_loop)

    def reset_game(self):
        # 取消定时器（如果存在）
        if self.after_id is not None:
            try:
                self.after_cancel(self.after_id)
            except Exception:
                pass
            self.after_id = None

        self.running = False
        self.paused = False
        self.elapsed = 0.0
        self.score = 0
        self.life = MAX_LIFE
        self.life_var.set(str(self.life))
        self.score_var.set(str(self.score))
        self.time_var.set("0.0")

        # 重置车辆
        self.car.x = (self.track_x0 + self.track_x1) / 2
        self.car.y = self.track_y1 - 60
        self.car.vx = 0.0
        self.car.vy = 0.0

        # 生成障碍
        self.generate_obstacles()
        # 初次绘制
        self.draw()

    def generate_obstacles(self):
        self.obstacles.clear()
        tries_limit = 200
        for _ in range(OBSTACLE_COUNT):
            for _ in range(tries_limit):
                x = random.uniform(self.track_x0 + 30, self.track_x1 - 30)
                y = random.uniform(self.track_y0 + 80, self.track_y1 - 80)
                # 避免太靠近起点
                if abs(x - self.car.x) < 80 and abs(y - self.car.y) < 80:
                    continue
                ok = True
                for ob in self.obstacles:
                    if abs(ob.x - x) < 50 and abs(ob.y - y) < 50:
                        ok = False
                        break
                if ok:
                    self.obstacles.append(Obstacle(x, y))
                    break

    def game_loop(self):
        # 主循环（由 after 调用）
        self.after_id = None  # 当前调用已被触发
        if not self.running:
            return
        if not self.paused:
            now = time.time()
            self.elapsed = now - self.start_time
            self.time_var.set(f"{self.elapsed:.1f}")
            self.update_physics()
            self.check_collisions()
            # 计分：基于时间与通过障碍的简单加分
            self.score += 0.02
            self.score_var.set(str(int(self.score)))
            self.draw()
        # 继续下一帧
        self.after_id = self.after(16, self.game_loop)

    def update_physics(self):
        acc = 0.35
        max_sp = self.car.max_speed

        up = self.keys.get("Up") or self.keys.get("w")
        down = self.keys.get("Down") or self.keys.get("s")
        left = self.keys.get("Left") or self.keys.get("a")
        right = self.keys.get("Right") or self.keys.get("d")

        # 加速度
        if up and not down:
            self.car.vy = max(self.car.vy - acc, -max_sp)
        elif down and not up:
            self.car.vy = min(self.car.vy + acc, max_sp)
        else:
            self.car.vy *= 0.88
            if abs(self.car.vy) < 0.05:
                self.car.vy = 0.0

        if left and not right:
            self.car.vx = max(self.car.vx - acc, -max_sp)
        elif right and not left:
            self.car.vx = min(self.car.vx + acc, max_sp)
        else:
            self.car.vx *= 0.88
            if abs(self.car.vx) < 0.05:
                self.car.vx = 0.0

        # 更新位置
        self.car.x += self.car.vx
        self.car.y += self.car.vy

        # 限制至赛道内（与墙体反弹）
        margin_x = self.track_x0 + self.car.size/2
        margin_x2 = self.track_x1 - self.car.size/2
        margin_y = self.track_y0 + self.car.size/2
        margin_y2 = self.track_y1 - self.car.size/2

        if self.car.x < margin_x:
            self.car.x = margin_x
            self.car.vx *= -0.35
        if self.car.x > margin_x2:
            self.car.x = margin_x2
            self.car.vx *= -0.35
        if self.car.y < margin_y:
            self.car.y = margin_y
            self.car.vy *= -0.35
        if self.car.y > margin_y2:
            self.car.y = margin_y2
            self.car.vy *= -0.35

    def check_collisions(self):
        # 碰撞检测（矩形）
        cx0, cy0, cx1, cy1 = self.car.rect()
        hit = False
        for ob in self.obstacles:
            ox0, oy0, ox1, oy1 = ob.rect()
            if not (cx1 < ox0 or cx0 > ox1 or cy1 < oy0 or cy0 > oy1):
                hit = True
                # 扣血、惩罚得分并反弹
                self.life -= 1
                self.life_var.set(str(self.life))
                self.score = max(0, self.score - 8)
                self.score_var.set(str(int(self.score)))
                # 推开车辆
                dx = self.car.x - ob.x
                dy = self.car.y - ob.y
                if dx == 0 and dy == 0:
                    dx = 1.0
                dist = (dx*dx + dy*dy) ** 0.5
                self.car.x += (dx / dist) * 28
                self.car.y += (dy / dist) * 28
                self.car.vx *= -0.45
                self.car.vy *= -0.45
                break

        if hit and self.life <= 0:
            self.game_over(False)

        # 胜利条件：到达终点线（赛道上方中间区域）
        fx0 = (self.track_x0 + self.track_x1) / 2 - 60
        fx1 = (self.track_x0 + self.track_x1) / 2 + 60
        finish_y = self.track_y0 + 12
        if (fx0 <= self.car.x <= fx1) and (self.car.y - self.car.size/2 <= finish_y):
            self.game_over(True)

    def game_over(self, win):
        self.running = False
        # 取消定时器
        if self.after_id is not None:
            try:
                self.after_cancel(self.after_id)
            except Exception:
                pass
            self.after_id = None

        if win:
            messagebox.showinfo("胜利", f"恭喜罗小黑到达终点！ 得分：{int(self.score)} 用时：{self.time_var.get()}s")
        else:
            messagebox.showinfo("失败", f"生命耗尽，游戏结束！ 得分：{int(self.score)}")

        # 自动重置
        self.reset_game()

    def draw(self):
        self.canvas.delete("all")
        W = WINDOW_W
        H = WINDOW_H - UI_HEIGHT

        # 背景
        self.canvas.create_rectangle(0, 0, W, H, fill=BG_COLOR, outline="")

        # 赛道
        self.canvas.create_rectangle(self.track_x0, self.track_y0, self.track_x1, self.track_y1, fill=ROAD_COLOR, outline="black", width=2)

        # 中线虚线
        midx = (self.track_x0 + self.track_x1) / 2
        dash_h = 20
        gap = 12
        y = self.track_y0 + 10
        while y < self.track_y1 - 10:
            y2 = min(y + dash_h, self.track_y1 - 10)
            self.canvas.create_line(midx, y, midx, y2, fill=LINE_COLOR, width=4)
            y += dash_h + gap

        # 终点线
        fx0 = (self.track_x0 + self.track_x1) / 2 - 60
        fx1 = (self.track_x0 + self.track_x1) / 2 + 60
        self.canvas.create_rectangle(fx0, self.track_y0, fx1, self.track_y0+10, fill=FINISH_COLOR, outline="black")

        # 障碍物（红色方块）
        for ob in self.obstacles:
            x0, y0, x1, y1 = ob.rect()
            self.canvas.create_rectangle(x0, y0, x1, y1, fill=OBST_COLOR, outline="#7b1f1f")

        # 绘制车（用圆形+眼睛表示罗小黑）
        cx0, cy0, cx1, cy1 = self.car.rect()
        self.canvas.create_oval(cx0, cy0, cx1, cy1, fill=CAR_COLOR, outline="white", width=1.5)
        # 眼睛（白）
        eye_r = 3
        self.canvas.create_oval(self.car.x - 8 - eye_r, self.car.y - 8 - eye_r, self.car.x - 8 + eye_r, self.car.y - 8 + eye_r, fill="white", outline="")
        self.canvas.create_oval(self.car.x + 8 - eye_r, self.car.y - 8 - eye_r, self.car.x + 8 + eye_r, self.car.y - 8 + eye_r, fill="white", outline="")
        # 小嘴/表情（可选）
        self.canvas.create_arc(self.car.x-8, self.car.y-2, self.car.x+8, self.car.y+8, start=0, extent=180, style="arc", outline="white")

        # HUD（左上角）
        self.canvas.create_text(12, 12, anchor="nw", text=f"生命: {self.life}", fill="white", font=("TkDefaultFont", 12, "bold"))
        self.canvas.create_text(12, 30, anchor="nw", text=f"得分: {int(self.score)}", fill="white", font=("TkDefaultFont", 12))
        self.canvas.create_text(12, 48, anchor="nw", text=f"时间: {self.time_var.get()}s", fill="white", font=("TkDefaultFont", 12))

    # 可扩展：加载图像替换小车
    def load_car_image(self, path):
        # 示例：如果有图片（png），可用 PhotoImage
        # img = tk.PhotoImage(file=path)
        # self.car_image = img
        # 在 draw 中替换 create_oval 为 create_image
        pass

if __name__ == "__main__":
    app = GameApp()
    app.mainloop()