import pygame
import math
import random
import sys
from pygame.locals import *

# 初始化Pygame
pygame.init()
pygame.mixer.init()

# 游戏设置
SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
FPS = 60

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 155, 0)
BLUE = (30, 144, 254)
YELLOW = (255, 165, 0)
GRAY = (100, 100, 100)
DARK_GRAY = (50, 50, 50)
SKY_BLUE = (135, 206, 235)
GRASS_GREEN = (34, 139, 34)
ORANGE = (255, 127, 0)
PURPLE = (138, 43, 226)

class Car:
    def __init__(self):
        self.x = 0
        self.y = 0
        self.z = 0
        self.speed = 0
        self.max_speed = 320
        self.acceleration = 6
        self.brake_deceleration = 10
        self.natural_deceleration = 2
        self.steering = 0
        self.max_steering = 220
        self.steering_speed = 175
        self.width = 420
        self.length = 750
        self.color = BLUE
        self.upgrades = {
            'engine': 1,
            'tires': 1,
            'brakes': 1,
            'aero': 1
        }
        
    def apply_upgrades(self):
        engine_bonus = self.upgrades['engine'] * 0.1
        tire_bonus = self.upgrades['tires'] * 0.08
        brake_bonus = self.upgrades['brakes'] * 0.15
        
        self.max_speed = 320 * (1 + engine_bonus)
        self.acceleration = 6 * (1 + engine_bonus * 0.8)
        self.max_steering = 220 * (1 + tire_bonus)
        self.brake_deceleration = 10 * (1 + brake_bonus)
        
    def update(self, dt, keys):
        # 加速
        if keys[K_UP] or keys[K_w]:
            self.speed = min(self.speed + self.acceleration * dt * 60, self.max_speed)
        # 刹车
        elif keys[K_DOWN] or keys[K_s]:
            self.speed = max(self.speed - self.brake_deceleration * dt * 60, 0)
        else:
            if self.speed > 0:
                self.speed = max(self.speed - self.natural_deceleration * dt * 60, 0)
        
        # 转向
        if keys[K_LEFT] or keys[K_a]:
            self.steering = min(self.steering + self.steering_speed * dt, self.max_steering)
        elif keys[K_RIGHT] or keys[K_d]:
            self.steering = max(self.steering - self.steering_speed * dt, -self.max_steering)
        else:
            if abs(self.steering) < 5:
                self.steering = 0
            else:
                self.steering -= self.steering * 0.08 * dt * 60
        
        # 移动
        if self.speed > 0:
            turn_factor = self.speed / self.max_speed
            steering_angle = self.steering * turn_factor * 0.002
            
            self.x += math.sin(steering_angle) * self.speed * dt
            self.z += math.cos(steering_angle) * self.speed * dt
        
        # 赛道边界
        track_width = 5500
        if abs(self.x) > track_width:
            self.x = track_width if self.x > 0 else -track_width
            self.speed *= 0.3

class AICar:
    def __init__(self, difficulty='medium'):
        self.x = random.uniform(-2000, 2000)
        self.z = -500
        self.speed = random.uniform(100, 200)
        self.max_speed = {'easy': 150, 'medium': 230, 'hard': 310}[difficulty]
        self.accuracy = {'easy': 0.3, 'medium': 0.6, 'hard': 0.85}[difficulty]
        self.steering = 0
        self.color = random.choice([RED, YELLOW, ORANGE, PURPLE])
        self.target_x = 0
        
    def update(self, dt, track_segments):
        # AI驾驶逻辑
        if track_segments:
            nearest_seg = track_segments[len(track_segments)//2]
            self.target_x = (nearest_seg['points'][0][0] + nearest_seg['points'][1][0]) / 2
        
        error = self.target_x - self.x
        self.steering = error * 0.01 * self.accuracy
        self.steering += random.uniform(-0.5, 0.5) * (1 - self.accuracy)
        
        # 加速
        self.speed = min(self.speed + 2, self.max_speed)
        
        # 移动
        steering_angle = self.steering * 0.003
        self.x += math.sin(steering_angle) * self.speed * dt
        self.z += math.cos(steering_angle) * self.speed * dt

class Track:
    def __init__(self, track_type='circuit'):
        self.segments = []
        self.track_type = track_type
        self.generate_track()
        
    def generate_track(self):
        num_segments = 720
        track_radius = 3500
        track_width = 4800
        
        for i in range(num_segments):
            angle = (i / num_segments) * 2 * math.pi
            next_angle = ((i + 1) / num_segments) * 2 * math.pi
            
            # 添加地形起伏
            elevation = math.sin(angle * 3) * 200 + math.cos(angle * 5) * 100
            
            segment = {
                'angle': angle,
                'inner_radius': track_radius - track_width // 2,
                'outer_radius': track_radius + track_width // 2,
                'elevation': elevation,
                'points': [],
                'decorations': []
            }
            
            # 赛道点
            inner_x = math.cos(angle) * segment['inner_radius']
            inner_z = math.sin(angle) * segment['inner_radius']
            outer_x = math.cos(angle) * segment['outer_radius']
            outer_z = math.sin(angle) * segment['outer_radius']
            
            segment['points'] = [
                (inner_x, elevation, inner_z),
                (outer_x, elevation, outer_z),
                (math.cos(next_angle) * segment['outer_radius'], elevation, 
                 math.sin(next_angle) * segment['outer_radius']),
                (math.cos(next_angle) * segment['inner_radius'], elevation,
                 math.sin(next_angle) * segment['inner_radius'])
            ]
            
            # 装饰物
            if random.random() < 0.015:
                deco_type = random.choice(['tree', 'sign', 'light'])
                deco_pos = (
                    math.cos(angle) * (segment['outer_radius'] + 200),
                    elevation,
                    math.sin(angle) * (segment['outer_radius'] + 200)
                )
                segment['decorations'].append({'type': deco_type, 'pos': deco_pos})
            
            self.segments.append(segment)

class WeatherSystem:
    def __init__(self):
        self.weather_types = ['sunny', 'rainy', 'foggy', 'night']
        self.current_weather = 'sunny'
        self.transition_time = 0
        self.raindrops = []
        
    def change_weather(self, new_weather):
        if new_weather != self.current_weather:
            self.current_weather = new_weather
            self.transition_time = 0
            
    def update(self, dt):
        self.transition_time += dt
        
        if self.current_weather == 'rainy':
            # 生成雨滴
            if random.random() < 0.3:
                self.raindrops.append({
                    'x': random.randint(0, SCREEN_WIDTH),
                    'y': -10,
                    'speed': random.uniform(8, 15),
                    'length': random.uniform(5, 15)
                })
            
            # 更新雨滴
            for drop in self.raindrops[:]:
                drop['y'] += drop['speed']
                if drop['y'] > SCREEN_HEIGHT:
                    self.raindrops.remove(drop)
                    
    def apply_effects(self, game):
        if self.current_weather == 'rainy':
            game.car.natural_deceleration = 3
            game.view_distance = 3000
        elif self.current_weather == 'foggy':
            game.car.natural_deceleration = 2
            game.view_distance = 1500
        elif self.current_weather == 'night':
            game.view_distance = 2000
        else:
            game.car.natural_deceleration = 2
            game.view_distance = 5000
            
    def draw_effects(self, screen):
        if self.current_weather == 'rainy':
            for drop in self.raindrops:
                pygame.draw.line(screen, (200, 200, 255), 
                               (drop['x'], drop['y']),
                               (drop['x'], drop['y'] + drop['length']), 1)

class Game:
    def __init__(self):
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("3D赛车 - 终极驾驶体验")
        self.clock = pygame.time.Clock()
        self.running = True
        self.paused = False
        self.score = 0
        self.laps = 0
        self.game_state = 'menu'  # menu, playing, paused, gameover
        
        self.car = Car()
        self.ai_cars = [AICar('medium') for _ in range(3)]
        self.track = Track()
        self.weather = WeatherSystem()
        
        # 相机参数
        self.fov = 512
        self.view_distance = 5000
        self.player_height = 650
        
        # 菜单选项
        self.menu_options = [
            ('开始比赛', lambda: self.start_race()),
            ('选择赛道', lambda: self.select_track()),
            ('车辆改装', lambda: self.open_garage()),
            ('天气设置', lambda: self.weather_settings()),
            ('退出游戏', lambda: sys.exit())
        ]
        self.selected_option = 0
        
    def start_race(self):
        self.game_state = 'playing'
        self.score = 0
        self.laps = 0
        self.car = Car()
        self.car.apply_upgrades()
        
    def select_track(self):
        track_types = ['circuit', 'oval', 'sprint']
        current = track_types.index(self.track.track_type)
        self.track.track_type = track_types[(current + 1) % len(track_types)]
        self.track.generate_track()
        
    def open_garage(self):
        upgrade_types = ['engine', 'tires', 'brakes', 'aero']
        current_upgrade = 0
        
        upgrading = True
        while upgrading:
            self.screen.fill(DARK_GRAY)
            font = pygame.font.Font(None, 42)
            
            title = font.render("车辆改装", True, WHITE)
            title_rect = title.get_rect(center=(SCREEN_WIDTH//2, 80))
            self.screen.blit(title, title_rect)
            
            for i, upgrade in enumerate(upgrade_types):
                level = self.car.upgrades[upgrade]
                color = YELLOW if i == current_upgrade else WHITE
                text = font.render(f"{upgrade.upper()}: 等级 {level}/5", True, color)
                text_rect = text.get_rect(center=(SCREEN_WIDTH//2, 200 + i*70))
                self.screen.blit(text, text_rect)
            
            info_font = pygame.font.Font(None, 28)
            info = info_font.render("↑↓选择 ↑↓升级 | ESC返回", True, WHITE)
            info_rect = info.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT-50))
            self.screen.blit(info, info_rect)
            
            pygame.display.flip()
            
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        upgrading = False
                    elif event.key == K_UP:
                        current_upgrade = (current_upgrade - 1) % len(upgrade_types)
                    elif event.key == K_DOWN:
                        current_upgrade = (current_upgrade + 1) % len(upgrade_types)
                    elif event.key == K_RETURN:
                        if self.car.upgrades[upgrade_types[current_upgrade]] < 5:
                            self.car.upgrades[upgrade_types[current_upgrade]] += 1
                            self.car.apply_upgrades()
        
    def weather_settings(self):
        weather_types = ['sunny', 'rainy', 'foggy', 'night']
        current = weather_types.index(self.weather.current_weather)
        self.weather.current_weather = weather_types[(current + 1) % len(weather_types)]
        
    def project_3d_to_2d(self, point):
        dx = point[0] - self.car.x
        dy = point[1] - self.player_height
        dz = point[2] - self.car.z
        
        cos_a = math.cos(self.car.steering * 0.0008)
        sin_a = math.sin(self.car.steering * 0.0008)
        
        rotated_x = dx * cos_a - dz * sin_a
        rotated_z = dx * sin_a + dz * cos_a
        
        if rotated_z <= 0:
            return None
        
        scale = self.fov / rotated_z
        screen_x = SCREEN_WIDTH // 2 + int(rotated_x * scale)
        screen_y = SCREEN_HEIGHT // 2 - int(dy * scale)
        
        return (screen_x, screen_y, rotated_z)
    
    def draw_sky(self):
        colors = [(135, 186, 225), (145, 196, 235), (155, 208, 242), (168, 218, 247)]
        
        if self.weather.current_weather == 'night':
            colors = [(10, 10, 40), (15, 15, 50), (20, 20, 60), (25, 25, 70)]
            
            # 星星
            for _ in range(50):
                star_x = random.randint(0, SCREEN_WIDTH)
                star_y = random.randint(0, SCREEN_HEIGHT // 2)
                pygame.draw.circle(self.screen, WHITE, (star_x, star_y), 1)
        
        elif self.weather.current_weather == 'foggy':
            colors = [(180, 185, 190), (185, 192, 198), (195, 201, 207), (205, 212, 217)]
        
        for i, color in enumerate(colors):
            height = SCREEN_HEIGHT // 3
            rect = pygame.Rect(0, i * height // 4, SCREEN_WIDTH, height // 4 + 1)
            pygame.draw.rect(self.screen, color, rect)
    
    def draw_road(self):
        visible_segments = []
        
        for segment in self.track.segments:
            points_2d = []
            all_valid = True
            
            for p in segment['points']:
                projected = self.project_3d_to_2d(p)
                if projected is None:
                    all_valid = False
                    break
                points_2d.append(projected)
            
            if all_valid and points_2d[0][2] < self.view_distance:
                visible_segments.append((segment, points_2d))
        
        visible_segments.sort(key=lambda x: x[1][0][2], reverse=True)
        
        for segment, points in visible_segments:
            # 赛道颜色
            if segment['angle'] % 0.025 < 0.0125:
                road_color = GRAY
            else:
                road_color = (80, 82, 84)
            
            try:
                # 赛道主体
                pygame.draw.polygon(self.screen, road_color, 
                                  [(p[0], p[1]) for p in points])
                
                # 赛道边线
                line_width = max(1, int(3 - points[0][2] * 0.0005))
                pygame.draw.line(self.screen, WHITE, 
                               (points[0][0], points[0][1]),
                               (points[1][0], points[1][1]), line_width)
                pygame.draw.line(self.screen, WHITE, 
                               (points[2][0], points[2][1]),
                               (points[3][0], points[3][1]), line_width)
                
                # 装饰物
                for deco in segment['decorations']:
                    proj_deco = self.project_3d_to_2d(deco['pos'])
                    if proj_deco:
                        size = max(3, 25 - proj_deco[2] * 0.004)
                        
                        if deco['type'] == 'tree':
                            pygame.draw.circle(self.screen, GREEN, 
                                             (int(proj_deco[0]), int(proj_deco[1] - size)),
                                             int(size))
                            pygame.draw.rect(self.screen, (101, 52, 17),
                                           (int(proj_deco[0] - 2), int(proj_deco[1]),
                                           4, int(size)))
                        elif deco['type'] == 'sign':
                            pygame.draw.rect(self.screen, WHITE,
                                           (int(proj_deco[0] - 5), int(proj_deco[1] - 10),
                                           10, 20))
                        elif deco['type'] == 'light':
                            color = YELLOW if self.weather.current_weather == 'night' else WHITE
                            pygame.draw.circle(self.screen, color, 
                                             (int(proj_deco[0]), int(proj_deco[1])), 3)
                            
            except:
                continue
    
    def draw_ai_cars(self):
        for ai_car in self.ai_cars:
            pos = (ai_car.x, 0, ai_car.z)
            projected = self.project_3d_to_2d(pos)
            if projected:
                size = max(5, 40 - projected[2] * 0.008)
                pygame.draw.rect(self.screen, ai_car.color,
                               (int(projected[0] - size//2), 
                                int(projected[1] - size//2),
                                int(size), int(size)), border_radius=3)
    
    def draw_hud(self):
        font = pygame.font.Font(None, 44)
        small_font = pygame.font.Font(None, 28)
        
        # 速度显示
        speed_text = font.render(f"{int(self.car.speed)} km/h", True, WHITE)
        self.screen.blit(speed_text, (30, 30))
        
        # 速度条
        bar_width = 280
        bar_height = 25
        bar_x = 30
        bar_y = 80
        
        pygame.draw.rect(self.screen, DARK_GRAY, (bar_x, bar_y, bar_width, bar_height), border_radius=5)
        
        fill_width = int((self.car.speed / self.car.max_speed) * bar_width)
        speed_color = GREEN if self.car.speed < self.car.max_speed * 0.6 else \
                     YELLOW if self.car.speed < self.car.max_speed * 0.85 else RED
        pygame.draw.rect(self.screen, speed_color, (bar_x, bar_y, fill_width, bar_height), border_radius=5)
        
        # 圈数和分数
        lap_text = font.render(f"圈数: {self.laps}", True, WHITE)
        score_text = font.render(f"分数: {self.score}", True, WHITE)
        self.screen.blit(lap_text, (SCREEN_WIDTH - 200, 30))
        self.screen.blit(score_text, (SCREEN_WIDTH - 200, 80))
        
        # 仪表盘
        dash_rect = pygame.Rect(SCREEN_WIDTH//2 - 200, SCREEN_HEIGHT - 160, 440, 170)
        pygame.draw.rect(self.screen, (30, 30, 37), dash_rect, border_radius=15)
        pygame.draw.rect(self.screen, (60, 62, 68), dash_rect, 2, border_radius=15)
        
        # 方向盘指示器
        steer_norm = self.car.steering / self.car.max_steering
        center_x = SCREEN_WIDTH // 2
        center_y = SCREEN_HEIGHT - 80
        
        pygame.draw.circle(self.screen, (50, 51, 57), (center_x, center_y), 40, 2)
        end_x = center_x + int(steer_norm * 35)
        end_y = center_y - 5
        pygame.draw.line(self.screen, YELLOW, (center_x, center_y), (end_x, end_y), 3)
        
        # 转速表
        rpm = int((self.car.speed / self.car.max_speed) * 100)
        rpm_text = small_font.render(f"转速: {rpm}%", True, YELLOW if rpm < 85 else RED)
        self.screen.blit(rpm_text, (SCREEN_WIDTH//2 - 50, SCREEN_HEIGHT - 140))
        
        # 天气信息
        weather_text = small_font.render(f"天气: {self.weather.current_weather}", True, WHITE)
        self.screen.blit(weather_text, (30, SCREEN_HEIGHT - 30))
        
        # 暂停提示
        if self.paused:
            pause_font = pygame.font.Font(None, 74)
            pause_text = pause_font.render("游戏暂停", True, WHITE)
            pause_rect = pause_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
            self.screen.blit(pause_text, pause_rect)
    
    def draw_menu(self):
        self.screen.fill(BLACK)
        
        # 标题
        title_font = pygame.font.Font(None, 86)
        subtitle_font = pygame.font.Font(None, 46)
        
        title = title_font.render("🏎️ 3D赛车", True, BLUE)
        title_rect = title.get_rect(center=(SCREEN_WIDTH//2, 120))
        self.screen.blit(title, title_rect)
        
        subtitle = subtitle_font.render("终极驾驶体验", True, WHITE)
        subtitle_rect = subtitle.get_rect(center=(SCREEN_WIDTH//2, 190))
        self.screen.blit(subtitle, subtitle_rect)
        
        # 菜单选项
        for i, (text, action) in enumerate(self.menu_options):
            color = YELLOW if i == self.selected_option else WHITE
            option_font = pygame.font.Font(None, 56)
            option_text = option_font.render(text, True, color)
            option_rect = option_text.get_rect(center=(SCREEN_WIDTH//2, 330 + i * 78))
            
            if i == self.selected_option:
                pygame.draw.rect(self.screen, (40, 41, 47), 
                               (option_rect.left - 20, option_rect.top - 10,
                                option_rect.width + 40, option_rect.height + 20),
                               border_radius=10)
            
            self.screen.blit(option_text, option_rect)
        
        # 底部信息
        info_font = pygame.font.Font(None, 28)
        info = info_font.render("↑↓ 选择  回车确认", True, WHITE)
        info_rect = info.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT - 60))
        self.screen.blit(info, info_rect)
    
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == QUIT:
                self.running = False
                return
            
            if self.game_state == 'menu':
                if event.type == KEYDOWN:
                    if event.key == K_UP:
                        self.selected_option = (self.selected_option - 1) % len(self.menu_options)
                    elif event.key == K_DOWN:
                        self.selected_option = (self.selected_option + 1) % len(self.menu_options)
                    elif event.key == K_RETURN:
                        self.menu_options[self.selected_option][1]()
                    elif event.key == K_ESCAPE:
                        self.running = False
                        
            elif self.game_state == 'playing':
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        self.paused = not self.paused
                    elif event.key == K_m:
                        self.game_state = 'menu'
                    elif event.key == K_w:
                        self.weather.change_weather(
                            random.choice(['sunny', 'rainy', 'foggy', 'night'])
                        )
    
    def run(self):
        while self.running:
            dt = self.clock.tick(FPS) / 1000.0
            self.handle_events()
            
            if self.game_state == 'menu':
                self.draw_menu()
                
            elif self.game_state == 'playing':
                if not self.paused:
                    keys = pygame.key.get_pressed()
                    
                    # 更新
                    self.car.update(dt, keys)
                    self.weather.update(dt)
                    self.weather.apply_effects(self)
                    
                    for ai_car in self.ai_cars:
                        ai_car.update(dt, self.track.segments)
                    
                    # 更新分数
                    self.score += int(self.car.speed * dt)
                    
                    # 检查圈数
                    if self.car.z < -3500 and self.car.z > -3600:
                        self.laps += 1
                
                # 绘制
                self.screen.fill(BLACK)
                self.draw_sky()
                
                grass_rect = pygame.Rect(0, SCREEN_HEIGHT // 2, SCREEN_WIDTH, SCREEN_HEIGHT // 2)
                pygame.draw.rect(self.screen, GRASS_GREEN, grass_rect)
                
                self.draw_road()
                self.draw_ai_cars()
                self.weather.draw_effects(self.screen)
                self.draw_hud()
            
            pygame.display.flip()
        
        pygame.quit()
        sys.exit()

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