import tkinter as tk
import math
import time
import random

# 窗口和赛道配置
WIDTH, HEIGHT = 800, 600
FPS = 60
DT = 1.0 / FPS

# 颜色
ROAD_COLOR = "#444444"
GRASS_COLOR = "#2e8b57"
CAR_COLOR = "#ff3333"
AI_COLOR = "#3377ff"
WALL_COLOR = "#222222"
CHECKPOINT_COLOR = "#ffd700"

# 车辆参数
MAX_SPEED = 400.0       # 像素/秒
ACCELERATION = 800.0    # 像素/秒^2
BRAKE_DECEL = 1200.0
TURN_SPEED = 180.0      # 度/秒 at full steering when moving
FRICTION = 400.0        # 摩擦减速

class Car:
    def __init__(self, x, y, angle=0.0, color=CAR_COLOR):
        self.x = x
        self.y = y
        self.v = 0.0          # 速度（像素/秒）
        self.angle = angle    # 朝向角度，度为单位，0 指向右
        self.steer = 0.0      # -1 左转，+1 右转
        self.acc = 0.0        # -1 刹车，+1 加速
        self.length = 20
        self.width = 12
        self.color = color
        self.rect_id = None

    def update(self, dt, track_mask=None):
        # 更新速度
        if self.acc > 0:
            self.v += ACCELERATION * self.acc * dt
        elif self.acc < 0:
            self.v += BRAKE_DECEL * self.acc * dt  # acc 负值，减速更快
        else:
            # 摩擦
            if self.v > 0:
                self.v -= FRICTION * dt
                if self.v < 0:
                    self.v = 0
            elif self.v < 0:
                self.v += FRICTION * dt
                if self.v > 0:
                    self.v = 0

        # 限速（允许倒车少量速度）
        if self.v > MAX_SPEED:
            self.v = MAX_SPEED
        if self.v < -MAX_SPEED * 0.5:
            self.v = -MAX_SPEED * 0.5

        # 转向与位移（转向与速度成比例）
        if abs(self.v) > 1.0:
            # 转向角度与速度方向的符号相关（倒车时转向反向）
            v_sign = 1 if self.v >= 0 else -1
            turning = TURN_SPEED * self.steer * (abs(self.v) / MAX_SPEED) * v_sign
            self.angle += turning * dt

        # 更新位置
        rad = math.radians(self.angle)
        dx = math.cos(rad) * self.v * dt
        dy = math.sin(rad) * self.v * dt
        self.x += dx
        self.y += dy

        # 若提供 track_mask（用于简单碰撞检测），在碰撞时反弹并减速
        if track_mask is not None:
            # 检测车中心点是否在道路 (track_mask 返回 True 表示可通行)
            if not track_mask(int(self.x), int(self.y)):
                # 碰撞：退回并大幅减速
                self.x -= dx
                self.y -= dy
                self.v *= -0.3
                # 小幅偏移避免卡住
                self.x += random.uniform(-2, 2)
                self.y += random.uniform(-2, 2)

    def corners(self):
        # 返回车四个角的坐标（用于更精确的碰撞检测）
        rad = math.radians(self.angle)
        cos_a = math.cos(rad)
        sin_a = math.sin(rad)
        l = self.length
        w = self.width
        # 以车中心为原点，四个角相对坐标
        pts = [
            ( l/2,  w/2),
            ( l/2, -w/2),
            (-l/2, -w/2),
            (-l/2,  w/2),
        ]
        world = []
        for px, py in pts:
            wx = self.x + px * cos_a - py * sin_a
            wy = self.y + px * sin_a + py * cos_a
            world.append((wx, wy))
        return world

class RacingApp:
    def __init__(self, master):
        self.master = master
        master.title("2D 赛车 (Tkinter)")

        self.canvas = tk.Canvas(master, width=WIDTH, height=HEIGHT, bg=GRASS_COLOR)
        self.canvas.pack()

        # 赛道约定：使用矩形环形赛道示例（可替换为更复杂图片或路径）
        self.track_outer = (100, 60, WIDTH-100, HEIGHT-60)   # 外矩形 (x0,y0,x1,y1)
        self.track_inner = (220, 160, WIDTH-220, HEIGHT-160) # 内矩形为草地
        # 简单检查点放在右侧通道
        self.checkpoints = [
            ((self.track_outer[2]+self.track_inner[2]) / 2, HEIGHT/2),
        ]
        self.current_checkpoint = 0

        # 创建道路掩码用于碰撞检测（True 表示道路）
        self.track_mask = self.build_track_mask()

        # 车辆初始化（起点在赛道左下）
        start_x = (self.track_outer[0] + self.track_inner[0]) / 2 + 10
        start_y = (self.track_outer[3] + self.track_inner[3]) / 2 - 20
        self.player = Car(start_x, start_y, angle=0.0, color=CAR_COLOR)
        # 一个简单 AI 对手沿固定路径巡航
        self.ai = Car(start_x, start_y-40, angle=0.0, color=AI_COLOR)
        self.ai_path = self.build_ai_path()
        self.ai_target_idx = 0

        # 控制状态
        self.pressing = {"up": False, "down": False, "left": False, "right": False}
        self.laps = 0
        self.start_time = None
        self.running = True

        # UI 文本
        self.speed_text = self.canvas.create_text(10, 10, anchor="nw", fill="white", font=("Arial", 12),
                                                  text="Speed: 0")
        self.time_text = self.canvas.create_text(10, 30, anchor="nw", fill="white", font=("Arial", 12),
                                                 text="Time: 0.00")
        self.lap_text = self.canvas.create_text(10, 50, anchor="nw", fill="white", font=("Arial", 12),
                                                text="Laps: 0")

        # 按钮
        self.btn_frame = tk.Frame(master)
        self.btn_frame.pack(fill="x")
        tk.Button(self.btn_frame, text="重置", command=self.reset).pack(side="left", padx=5)
        tk.Button(self.btn_frame, text="暂停/继续", command=self.toggle_pause).pack(side="left", padx=5)

        # 绑定键盘
        master.bind("<KeyPress>", self.on_key_press)
        master.bind("<KeyRelease>", self.on_key_release)

        # 启动循环
        self.last_time = time.time()
        self.loop()

    def build_track_mask(self):
        # 使用一个像素级掩码（二维布尔数组），用于快速判断点是否在道路上
        w, h = WIDTH, HEIGHT
        mask = [[False]*h for _ in range(w)]
        x0o, y0o, x1o, y1o = self.track_outer
        x0i, y0i, x1i, y1i = self.track_inner
        for x in range(w):
            for y in range(h):
                inside_outer = (x0o <= x <= x1o and y0o <= y <= y1o)
                inside_inner = (x0i <= x <= x1i and y0i <= y <= y1i)
                if inside_outer and not inside_inner:
                    mask[x][y] = True
        # 返回函数接口以节省内存/访问开销
        return lambda xx, yy: (0 <= xx < w and 0 <= yy < h and mask[xx][yy])

    def build_ai_path(self):
        # 构造一个围绕赛道中心的简单路径（多点），AI 将按点移动
        cx = (self.track_outer[0] + self.track_outer[2]) / 2
        cy = (self.track_outer[1] + self.track_outer[3]) / 2
        rx = (self.track_outer[2] - self.track_outer[0]) / 2 - 40
        ry = (self.track_outer[3] - self.track_outer[1]) / 2 - 40
        pts = []
        for i in range(12):
            a = 2*math.pi * i / 12
            pts.append((cx + math.cos(a)*rx, cy + math.sin(a)*ry))
        return pts

    def on_key_press(self, e):
        k = e.keysym.lower()
        if k in ("up", "w"):
            self.pressing["up"] = True
        elif k in ("down", "s"):
            self.pressing["down"] = True
        elif k in ("left", "a"):
            self.pressing["left"] = True
        elif k in ("right", "d"):
            self.pressing["right"] = True
        elif k == "r":
            self.reset()

    def on_key_release(self, e):
        k = e.keysym.lower()
        if k in ("up", "w"):
            self.pressing["up"] = False
        elif k in ("down", "s"):
            self.pressing["down"] = False
        elif k in ("left", "a"):
            self.pressing["left"] = False
        elif k in ("right", "d"):
            self.pressing["right"] = False

    def reset(self):
        # 重置玩家与时间
        start_x = (self.track_outer[0] + self.track_inner[0]) / 2 + 10
        start_y = (self.track_outer[3] + self.track_inner[3]) / 2 - 20
        self.player.x = start_x
        self.player.y = start_y
        self.player.v = 0
        self.player.angle = 0
        self.laps = 0
        self.current_checkpoint = 0
        self.start_time = time.time()
        self.running = True

    def toggle_pause(self):
        self.running = not self.running
        if self.running and self.start_time is None:
            self.start_time = time.time()

    def update_controls(self):
        # 根据按键设置加速度与转向
        if self.pressing["up"]:
            self.player.acc = 1.0
        elif self.pressing["down"]:
            self.player.acc = -1.0
        else:
            self.player.acc = 0.0

        steer = 0.0
        if self.pressing["left"]:
            steer -= 1.0
        if self.pressing["right"]:
            steer += 1.0
        self.player.steer = steer

    def update_ai(self, dt):
        # 简单追踪下一个路径点
        if not self.ai_path:
            return
        tx, ty = self.ai_path[self.ai_target_idx]
        dx = tx - self.ai.x
        dy = ty - self.ai.y
        dist = math.hypot(dx, dy)
        desired_angle = math.degrees(math.atan2(dy, dx))
        # 调整角度缓慢转向
        ang_diff = (desired_angle - self.ai.angle + 180) % 360 - 180
        self.ai.steer = max(-1.0, min(1.0, ang_diff / 45.0))
        # 简单速度控制
        self.ai.acc = 1.0 if dist > 30 else 0.0
        if dist < 20:
            self.ai_target_idx = (self.ai_target_idx + 1) % len(self.ai_path)
        self.ai.update(dt, track_mask=self.track_mask)

    def check_checkpoints(self):
        # 检查玩家是否通过当前检查点
        if not self.checkpoints:
            return
        cx, cy = self.checkpoints[self.current_checkpoint]
        if math.hypot(self.player.x - cx, self.player.y - cy) < 30:
            self.current_checkpoint += 1
            if self.current_checkpoint >= len(self.checkpoints):
                self.current_checkpoint = 0
                self.laps += 1

    def draw_track(self):
        self.canvas.delete("all")
        # 草地背景
        self.canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=GRASS_COLOR, outline=GRASS_COLOR)
        # 道路 (外矩形)
        x0o, y0o, x1o, y1o = self.track_outer
        x0i, y0i, x1i, y1i = self.track_inner
        self.canvas.create_rectangle(x0o, y0o, x1o, y1o, fill=ROAD_COLOR, outline=WALL_COLOR)
        # 内部草地孔
        self.canvas.create_rectangle(x0i, y0i, x1i, y1i, fill=GRASS_COLOR, outline=WALL_COLOR)
        # 绘制检查点
        for i, (cx, cy) in enumerate(self.checkpoints):
            color = CHECKPOINT_COLOR if i == self.current_checkpoint else "#cccc00"
            self.canvas.create_oval(cx-10, cy-10, cx+10, cy+10, fill=color, outline="")
        # 绘制边界线
        self.canvas.create_rectangle(x0o, y0o, x1o, y1o, outline=WALL_COLOR)
        self.canvas.create_rectangle(x0i, y0i, x1i, y1i, outline=WALL_COLOR)

    def draw_car(self, car):
        # 画旋转矩形表示车辆
        pts = car.corners()
        flat = [coord for p in pts for coord in p]
        if car.rect_id:
            self.canvas.delete(car.rect_id)
        car.rect_id = self.canvas.create_polygon(flat, fill=car.color, outline="black")

    def loop(self):
        now = time.time()
        elapsed = now - self.last_time
        if elapsed > 0.2:
            elapsed = DT  # 防止因拖延造成大步长
        self.last_time = now

        if self.running:
            # update controls & physics
            self.update_controls()
            self.player.update(elapsed, track_mask=self.track_mask)
            self.update_ai(elapsed)
            self.check_checkpoints()

            if self.start_time is None:
                self.start_time = time.time()

        # 重绘
        self.draw_track()
        self.draw_car(self.ai)
        self.draw_car(self.player)

        # UI 更新
        speed_display = int(self.player.v)
        self.canvas.itemconfigure(self.speed_text, text=f"Speed: {speed_display}")
        t = time.time() - self.start_time if self.start_time else 0.0
        self.canvas.itemconfigure(self.time_text, text=f"Time: {t:.2f}")
        self.canvas.itemconfigure(self.lap_text, text=f"Laps: {self.laps}")

        # 以固定 FPS 调度下一帧
        self.master.after(int(1000*DT), self.loop)

if __name__ == "__main__":
    root = tk.Tk()
    app = RacingApp(root)
    root.mainloop()