import pygame
import math
import sys
import random          # ★ 添加这一行

pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("赛车模拟器 - 强化视觉版")
clock = pygame.time.Clock()
FPS = 60

# ==================== 色彩 ====================
SKY_TOP = (70, 130, 180)
SKY_HORIZON = (200, 180, 160)
SUN_COLOR = (255, 240, 200)
MOUNTAIN_FAR = (80, 90, 100)
MOUNTAIN_NEAR = (100, 110, 120)
GRASS = (60, 110, 40)
ROAD_BASE = (75, 75, 75)
ROAD_STRIPE = (90, 90, 90)
CURB_RED = (210, 60, 60)
CURB_WHITE = (230, 230, 230)
LINE_COLOR = (200, 200, 200)
TREE_TRUNK = (90, 60, 30)
TREE_CROWN = (30, 100, 20)
LAMP_POLE = (100, 100, 100)
LAMP_LIGHT = (255, 230, 100)
BUSH = (70, 120, 50)
GUARDRAIL = (180, 180, 180)

# ==================== 参数 ====================
ROAD_WIDTH = 1800
LANE_COUNT = 3
SEGMENT_LENGTH = 200
VISIBLE_SEGMENTS = 200
CAMERA_HEIGHT = 1100
CAMERA_DEPTH = 300
MIN_DRAW_DIST = 120

OBJECT_SPACING = 500

MAX_SPEED = 3000
MAX_REVERSE = -500
ACCEL = 400
BRAKE = 600
DRAG = 80
STEER_SPEED = 2400

CURVE_AMP = 2200
CURVE_FREQ = 0.00028

# 字体
font_small = pygame.font.Font(None, 26)
font_medium = pygame.font.Font(None, 36)
font_large = pygame.font.Font(None, 50)

# ==================== 工具函数 ====================
def seeded_rand(seed):
    x = (seed * 9301 + 49297) % 233280
    return x / 233280.0

def get_curve(dist):
    return math.sin(dist * CURVE_FREQ) * CURVE_AMP

def get_road_objects(seg_dist):
    objs = []
    start = int(seg_dist) // OBJECT_SPACING * OBJECT_SPACING
    while start < seg_dist + SEGMENT_LENGTH:
        if seg_dist <= start < seg_dist + SEGMENT_LENGTH:
            seed = start // OBJECT_SPACING
            side = 1 if seeded_rand(seed*2) < 0.5 else -1
            r = seeded_rand(seed*2+1)
            if r < 0.4: typ = 'tree'
            elif r < 0.8: typ = 'lamp'
            else: typ = 'bush'
            offset = 150 + seeded_rand(seed*3) * 500
            x_off = side * (ROAD_WIDTH/2 + offset)
            objs.append({'x': x_off, 'type': typ, 'dist': start})
        start += OBJECT_SPACING
    return objs

# ==================== 天空渐变 + 太阳 ====================
def draw_sky(surface):
    for y in range(HEIGHT//2):
        t = y / (HEIGHT//2)
        r = int(SKY_TOP[0] + (SKY_HORIZON[0]-SKY_TOP[0])*t)
        g = int(SKY_TOP[1] + (SKY_HORIZON[1]-SKY_TOP[1])*t)
        b = int(SKY_TOP[2] + (SKY_HORIZON[2]-SKY_TOP[2])*t)
        pygame.draw.line(surface, (r,g,b), (0,y), (WIDTH,y))
    # 太阳
    sun_x = int(WIDTH * 0.8)
    sun_y = int(HEIGHT * 0.18)
    pygame.draw.circle(surface, SUN_COLOR, (sun_x, sun_y), 35)
    pygame.draw.circle(surface, (255,255,220), (sun_x, sun_y), 25)

# ==================== 远山层次 ====================
def draw_mountains(surface):
    # 第一层远山
    pts = [(0, HEIGHT//2)]
    for x in range(0, WIDTH+10, 60):
        h = math.sin(x*0.015) * 40 + math.sin(x*0.045) * 20 + 30
        pts.append((x, HEIGHT//2 - h))
    pts.append((WIDTH, HEIGHT//2))
    pygame.draw.polygon(surface, MOUNTAIN_FAR, pts)
    # 第二层近山
    pts2 = [(0, HEIGHT//2)]
    for x in range(0, WIDTH+10, 80):
        h = math.sin(x*0.02+1) * 30 + math.sin(x*0.05) * 15 + 20
        pts2.append((x, HEIGHT//2 - h))
    pts2.append((WIDTH, HEIGHT//2))
    pygame.draw.polygon(surface, MOUNTAIN_NEAR, pts2)

# ==================== 绘制道路 ====================
def draw_road(surface, player_x, segments):
    for i in range(len(segments)-1):
        s1 = segments[i]
        s2 = segments[i+1]
        z1 = s1['dist']
        z2 = s2['dist']
        if z1 < MIN_DRAW_DIST or z2 < MIN_DRAW_DIST:
            continue

        c1 = get_curve(z1)
        c2 = get_curve(z2)

        def proj(x_w, z):
            scale = CAMERA_DEPTH / max(z,0.1)
            sx = WIDTH/2 + scale * (x_w - player_x)
            sy = HEIGHT/2 - scale * (0 - CAMERA_HEIGHT)
            return sx, sy

        left1, right1 = c1 - ROAD_WIDTH/2, c1 + ROAD_WIDTH/2
        left2, right2 = c2 - ROAD_WIDTH/2, c2 + ROAD_WIDTH/2
        lane1_1 = c1 - ROAD_WIDTH/2 + ROAD_WIDTH/LANE_COUNT
        lane2_1 = c1 - ROAD_WIDTH/2 + 2*ROAD_WIDTH/LANE_COUNT
        lane1_2 = c2 - ROAD_WIDTH/2 + ROAD_WIDTH/LANE_COUNT
        lane2_2 = c2 - ROAD_WIDTH/2 + 2*ROAD_WIDTH/LANE_COUNT

        curb_left1, curb_left2 = left1-80, left2-80
        curb_right1, curb_right2 = right1+80, right2+80

        # 投影所有点
        l1x,l1y = proj(left1,z1); r1x,r1y = proj(right1,z1)
        l2x,l2y = proj(left2,z2); r2x,r2y = proj(right2,z2)

        # 路面：根据距离分段颜色（车道纹理）
        seg_color = ROAD_BASE if (i//3)%2==0 else ROAD_STRIPE
        pygame.draw.polygon(surface, seg_color, [(l1x,l1y),(r1x,r1y),(r2x,r2y),(l2x,l2y)])

        # 路肩红白
        cl1x,_ = proj(curb_left1,z1); cl2x,_ = proj(curb_left2,z2)
        cr1x,_ = proj(curb_right1,z1); cr2x,_ = proj(curb_right2,z2)
        pygame.draw.line(surface, CURB_RED, (cl1x,l1y), (cl2x,l2y), 5)
        pygame.draw.line(surface, CURB_WHITE, (l1x,l1y), (l2x,l2y), 3)
        pygame.draw.line(surface, CURB_WHITE, (r1x,r1y), (r2x,r2y), 3)
        pygame.draw.line(surface, CURB_RED, (cr1x,r1y), (cr2x,r2y), 5)

        # 车道虚线
        if z1 < 25000:
            ln1_1x,ln1_1y = proj(lane1_1,z1); ln1_2x,ln1_2y = proj(lane1_2,z2)
            pygame.draw.line(surface, LINE_COLOR, (ln1_1x,ln1_1y), (ln1_2x,ln1_2y), 2)
            ln2_1x,ln2_1y = proj(lane2_1,z1); ln2_2x,ln2_2y = proj(lane2_2,z2)
            pygame.draw.line(surface, LINE_COLOR, (ln2_1x,ln2_1y), (ln2_2x,ln2_2y), 2)

        # 路边物体（带阴影）
        for obj in get_road_objects(z1):
            world_x = c1 + obj['x']
            scale = CAMERA_DEPTH / max(z1,0.1)
            if scale < 0.02: continue
            sx, sy = proj(world_x, z1)
            typ = obj['type']
            # 大气透视：远处颜色偏灰
            fog = min(1.0, z1/40000)
            fade = (1-fog)*0.8 + 0.2

            if typ == 'tree':
                trunk_h = int(140*scale)
                trunk_w = int(14*scale)
                # 阴影
                pygame.draw.rect(surface, (20,20,20),
                                 (sx-trunk_w//2+4, sy-trunk_h+4, trunk_w, trunk_h))
                pygame.draw.rect(surface, tuple(int(c*fade) for c in TREE_TRUNK),
                                 (sx-trunk_w//2, sy-trunk_h, trunk_w, trunk_h))
                crown_r = int(65*scale)
                pygame.draw.circle(surface, tuple(int(c*fade*0.6) for c in (30,30,30)),
                                   (sx+3, sy-trunk_h-crown_r//2+3), crown_r)
                pygame.draw.circle(surface, tuple(int(c*fade) for c in TREE_CROWN),
                                   (sx, sy-trunk_h-crown_r//2), crown_r)
            elif typ == 'lamp':
                pole_h = int(180*scale)
                pole_w = int(7*scale)
                pygame.draw.rect(surface, (30,30,30),
                                 (sx-pole_w//2+3, sy-pole_h+3, pole_w, pole_h))
                pygame.draw.rect(surface, tuple(int(c*fade) for c in LAMP_POLE),
                                 (sx-pole_w//2, sy-pole_h, pole_w, pole_h))
                lr = int(22*scale)
                pygame.draw.circle(surface, tuple(int(c*fade) for c in LAMP_LIGHT),
                                   (sx, sy-pole_h), lr)
            elif typ == 'bush':
                br = int(40*scale)
                pygame.draw.circle(surface, (20,20,20), (sx+2, sy-br+2), br)
                pygame.draw.circle(surface, tuple(int(c*fade) for c in BUSH),
                                   (sx, sy-br), br)

# ==================== 速度线 ====================
def draw_speed_lines(surface, speed):
    if speed < 500: return
    intensity = min(1.0, speed/MAX_SPEED)
    num = int(8 * intensity)
    for _ in range(num):
        x = random.randint(0, WIDTH)
        y = random.randint(HEIGHT//2, HEIGHT-50)
        length = random.randint(20, 50) * intensity
        alpha = random.randint(80, 180)
        line_surf = pygame.Surface((4, length), pygame.SRCALPHA)
        line_surf.fill((255,255,255, alpha))
        screen.blit(line_surf, (x, y))

# ==================== 仪表盘 ====================
def draw_hud(surface, speed, gear, distance):
    # 半透明背景
    hud = pygame.Surface((WIDTH, 140), pygame.SRCALPHA)
    hud.fill((0,0,0,170))
    surface.blit(hud, (0, HEIGHT-140))

    # 速度表
    cx, cy = 110, HEIGHT-65
    r = 55
    pygame.draw.circle(surface, (20,20,20), (cx,cy), r+6)
    pygame.draw.circle(surface, (10,10,10), (cx,cy), r)
    for i in range(0, 180, 20):
        ang = math.radians(220 - i)
        x1 = cx + math.cos(ang)*(r-10); y1 = cy - math.sin(ang)*(r-10)
        x2 = cx + math.cos(ang)*r; y2 = cy - math.sin(ang)*r
        pygame.draw.line(surface, (180,180,180), (x1,y1), (x2,y2), 2)
    # 指针
    kmh = int(speed * 0.1)
    ang = math.radians(220 - (kmh/300)*180)
    ang = max(math.radians(40), min(math.radians(220), ang))
    nx = cx + math.cos(ang)*(r-15); ny = cy - math.sin(ang)*(r-15)
    color = (255,80,80) if speed>=0 else (255,255,0)
    pygame.draw.line(surface, color, (cx,cy), (nx,ny), 4)
    txt = font_medium.render(str(kmh), True, (255,255,255))
    surface.blit(txt, (cx-20, cy+15))

    # 转速表（伪）
    rpm = int(abs(speed) / MAX_SPEED * 8)
    rpm_text = font_small.render(f"x1000rpm {rpm}", True, (200,200,200))
    surface.blit(rpm_text, (cx-30, cy+40))

    # 档位
    gear_txt = font_large.render(str(gear), True, (255,255,255))
    surface.blit(gear_txt, (cx+80, cy-30))
    font_small.render("GEAR", True, (180,180,180))
    surface.blit(font_small.render("GEAR", True, (180,180,180)), (cx+85, cy-10))

    # 里程
    dist_txt = font_small.render(f"ODO: {int(distance)} m", True, (200,200,200))
    surface.blit(dist_txt, (WIDTH-170, HEIGHT-110))

    # 状态
    if speed > 10: state = "▶ DRIVE"
    elif speed < -10: state = "◀ REVERSE"
    else: state = "■ STOP"
    state_s = font_medium.render(state, True, (50,200,50) if speed>10 else ((220,80,80) if speed<-10 else (180,180,180)))
    surface.blit(state_s, (WIDTH//2-50, HEIGHT-130))

# ==================== 游戏主类 ====================
class Game:
    def __init__(self):
        self.player_x = 0.0
        self.speed = 800.0
        self.distance = 300.0
        self.gear = 1
        self.segments = [{'dist': self.distance + i*SEGMENT_LENGTH} for i in range(VISIBLE_SEGMENTS)]

    def handle_input(self, dt):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_r]:
            self.player_x = get_curve(self.distance)
            self.speed = 800.0
            for i, seg in enumerate(self.segments):
                seg['dist'] = self.distance + i*SEGMENT_LENGTH
            return

        if keys[pygame.K_UP] or keys[pygame.K_w]:
            self.speed += ACCEL * dt
        elif keys[pygame.K_DOWN] or keys[pygame.K_s]:
            self.speed -= BRAKE * dt
        else:
            if self.speed > 0:
                self.speed -= DRAG * dt
                if self.speed < 0: self.speed = 0
            elif self.speed < 0:
                self.speed += DRAG * dt
                if self.speed > 0: self.speed = 0
        self.speed = max(MAX_REVERSE, min(self.speed, MAX_SPEED))

        steer = 0
        if keys[pygame.K_LEFT] or keys[pygame.K_a]: steer = -1
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]: steer = 1
        if steer != 0:
            self.player_x += STEER_SPEED * (abs(self.speed)/MAX_SPEED) * dt * steer

        self.distance += self.speed * dt
        center = get_curve(self.distance)
        limit_left = center - ROAD_WIDTH/2 + 120
        limit_right = center + ROAD_WIDTH/2 - 120
        self.player_x = max(limit_left, min(self.player_x, limit_right))

        for i, seg in enumerate(self.segments):
            seg['dist'] = self.distance + i*SEGMENT_LENGTH

        abs_speed = abs(self.speed)
        if abs_speed < 500: self.gear = 1
        elif abs_speed < 1500: self.gear = 2
        elif abs_speed < 2500: self.gear = 3
        else: self.gear = 4

    def draw(self, surface):
        draw_sky(surface)
        draw_mountains(surface)
        pygame.draw.rect(surface, GRASS, (0, HEIGHT//2, WIDTH, HEIGHT//2))
        draw_road(surface, self.player_x, self.segments)
        draw_speed_lines(surface, self.speed)
        draw_hud(surface, self.speed, self.gear, self.distance)
        pygame.display.flip()

    def run(self):
        while True:
            dt = clock.tick(FPS)/1000.0
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    pygame.quit(); sys.exit()
            self.handle_input(dt)
            self.draw(screen)

if __name__ == "__main__":
    Game().run()