from ursina import *
import random, math

app = Ursina()

# ========== 游戏参数 ==========
LANES = [-2.5, 0, 2.5]
base_speed = 10
speed_increase = 0.3
game_speed = base_speed
score = 0
game_over = False

# ========== 场景 ==========
window.title = "3D Racing - Premium"
window.size = (800, 600)
Sky()

# 主方向光
DirectionalLight(parent=camera, rotation=(30, -20, 0), color=color.rgba(255,255,240,200))
AmbientLight(color=color.rgba(80,80,100,80))

# 地面
Entity(model='plane', scale=(40,1,600), texture='grass', position=(0,-0.2,0))

# 道路主体（沥青纹理）
road = Entity(model='cube', scale=(8,0.02,600), color=color.hex('#2c2c2c'),
              texture='white_cube', texture_scale=(8,300), position=(0,0,0))

# 车道标线（虚线）
for z in range(-290, 300, 8):
    Entity(model='cube', scale=(0.12,0.03,3), color=color.white, position=(-2.7,0.02,z))
    Entity(model='cube', scale=(0.12,0.03,3), color=color.white, position=(2.7,0.02,z))
    Entity(model='cube', scale=(0.1,0.03,2.5), color=color.yellow, position=(0,0.02,z+4))

# 护栏
for side in [-4.5,4.5]:
    for z in range(-290,300,4):
        Entity(model='cylinder', scale=(0.08,0.7,0.08), color=color.gray, position=(side,0.35,z))
    Entity(model='cube', scale=(0.1,0.1,600), color=color.rgb(192,192,192), position=(side,0.75,0))

# 路灯
for z in range(-280,300,40):
    Entity(model='cylinder', scale=(0.1,2,0.1), color=color.dark_gray, position=(0,1,z))
    Entity(model='sphere', scale=(0.25,0.25,0.25), color=color.yellow, position=(0,2.1,z))

# 树木（多层次）
for i in range(50):
    x = random.choice([-7,7])
    z = random.uniform(-290,290)
    Entity(model='cylinder', scale=(0.4,3,0.4), color=color.brown, position=(x,1.5,z))
    for j in range(3):
        Entity(model='sphere', scale=(1.5-j*0.3, 1.5-j*0.3, 1.5-j*0.3),
               color=color.rgb(20,70+j*25,20), position=(x,2.8+j*0.9,z))

# 建筑群（带窗户效果）
for z in range(-280,300,30):
    w = random.uniform(2,4)
    h = random.uniform(5,15)
    building = Entity(model='cube', scale=(w,h,3), color=color.rgb(70,70,80),
                      position=(random.choice([-9,9]), h/2, z))
    # 窗户（小方块）
    for wy in range(1, int(h), 2):
        for wz in [-1,0,1]:
            if random.random() < 0.6:
                Entity(model='cube', scale=(0.3,0.5,0.2), color=color.rgb(255,255,200),
                       position=(building.x, wy, z+wz))

# ========== 玩家车辆（精细建模）==========
class PlayerCar(Entity):
    def __init__(self):
        super().__init__(position=(0,0.3,5))
        self.lane_idx = 1
        self.target_lane = 1

        # 底盘
        self.chassis = Entity(model='cube', scale=(1.2,0.3,2.5), color=color.hex('#e63946'),
                              parent=self, position=(0,0.2,0))
        # 前挡风
        Entity(model='cube', scale=(1.0,0.15,0.8), color=color.hex('#a8dadc'),
               parent=self, position=(0,0.55,-0.3))
        # 后挡风
        Entity(model='cube', scale=(0.9,0.1,0.6), color=color.hex('#457b9d'),
               parent=self, position=(0,0.5,0.6))
        # 车顶
        Entity(model='cube', scale=(1.0,0.1,1.0), color=color.hex('#1d3557'),
               parent=self, position=(0,0.65,-0.1))
        # 车灯（发光）
        self.headlight_left = Entity(model='sphere', scale=(0.15,0.1,0.15), color=color.yellow,
                                     parent=self, position=(-0.45,0.25,-1.3))
        self.headlight_right = Entity(model='sphere', scale=(0.15,0.1,0.15), color=color.yellow,
                                      parent=self, position=(0.45,0.25,-1.3))
        # 尾翼
        Entity(model='cube', scale=(1.2,0.08,0.3), color=color.black,
               parent=self, position=(0,0.45,1.1))
        # 车轮（带轮毂）
        wheel_pos = [(-0.65,0,0.8),(0.65,0,0.8),(-0.65,0,-0.8),(0.65,0,-0.8)]
        self.wheels = []
        for pos in wheel_pos:
            wheel = Entity(model='cylinder', scale=(0.35,0.15,0.35), color=color.black,
                           parent=self, position=pos, rotation_x=90)
            # 轮毂装饰（银色 -> RGB）
            Entity(model='cylinder', scale=(0.2,0.16,0.2), color=color.rgb(192,192,192),
                   parent=wheel, rotation_x=0)
            self.wheels.append(wheel)

    def update(self):
        if game_over: return
        target_x = LANES[self.target_lane]
        self.x = lerp(self.x, target_x, 0.2*60*time.dt)
        # 车身倾斜
        self.rotation_z = (self.x - target_x) * 5
        # 车轮旋转
        for w in self.wheels:
            w.rotation_x += game_speed * time.dt * 20

    def move_left(self):
        if self.target_lane > 0: self.target_lane -= 1
    def move_right(self):
        if self.target_lane < 2: self.target_lane += 1

player = PlayerCar()

# 车灯点光源
player_light = PointLight(parent=player, position=(0,0.5,-1.5), color=color.rgb(255,240,200), intensity=0.8)

# 排气管火焰粒子
class ExhaustParticle(Entity):
    def __init__(self, pos):
        super().__init__(model='quad', color=color.orange, scale=0.1, position=pos, billboard=True)
        self.velocity = Vec3(random.uniform(-0.3,0.3), random.uniform(0.2,0.5), random.uniform(-0.3,0.3))
        self.life = 0.15
    def update(self):
        self.position += self.velocity * time.dt
        self.life -= time.dt
        if self.life <= 0: destroy(self)

def spawn_exhaust():
    offsets = [(-0.4, 0.15, 1.3), (0.4, 0.15, 1.3)]
    for off in offsets:
        pos = player.world_position + Vec3(off[0], off[1], off[2])
        ExhaustParticle(pos)

# ========== 障碍车辆 ==========
class EnemyCar(Entity):
    def __init__(self, lane):
        x = LANES[lane]
        z = random.uniform(50, 90)
        super().__init__(position=(x,0.3,z))
        # 车身
        Entity(model='cube', scale=(1.1,0.3,2.3), color=color.random_color(), parent=self, position=(0,0.2,0))
        Entity(model='cube', scale=(0.9,0.1,0.7), color=color.hex('#2b2d42'), parent=self, position=(0,0.5,-0.3))
        Entity(model='cube', scale=(0.9,0.1,0.5), color=color.hex('#8d99ae'), parent=self, position=(0,0.5,0.5))
        for pos in [(-0.6,0,0.7),(0.6,0,0.7),(-0.6,0,-0.7),(0.6,0,-0.7)]:
            Entity(model='cylinder', scale=(0.3,0.12,0.3), color=color.black, parent=self, position=pos, rotation_x=90)
        self.lane = lane

    def update(self):
        if game_over: return
        self.z -= game_speed * time.dt
        if self.z < -10: destroy(self)

# ========== 金币 ==========
class GoldCoin(Entity):
    def __init__(self, lane):
        x = LANES[lane]
        z = random.uniform(40, 80)
        super().__init__(model='circle', color=color.gold, scale=0.45, position=(x,1,z), rotation_x=90, double_sided=True)
        Entity(model='circle', color=color.yellow, scale=0.55, position=(0,0,-0.01), rotation_x=90, parent=self)
        self.lane = lane
    def update(self):
        if game_over: return
        self.z -= game_speed * time.dt
        self.rotation_z += 150 * time.dt
        if self.z < -10: destroy(self)

# ========== 粒子特效 ==========
class StarParticle(Entity):
    def __init__(self, pos, col):
        super().__init__(model='quad', color=col, scale=0.08, position=pos, billboard=True)
        self.velocity = Vec3(random.uniform(-1,1), random.uniform(1,3), random.uniform(-1,1))
        self.life = 0.5
    def update(self):
        self.position += self.velocity * time.dt
        self.velocity.y -= 6 * time.dt
        self.life -= time.dt
        if self.life <= 0: destroy(self)

# ========== 生成逻辑 ==========
def spawn_enemy(): EnemyCar(random.randint(0,2))
def spawn_coin(): GoldCoin(random.randint(0,2))

enemy_timer = coin_timer = 0
overlay_text = None

def input(key):
    global game_over, game_speed, score, enemy_timer, coin_timer, overlay_text
    if key == 'r' and game_over:
        game_over = False
        game_speed = base_speed
        score = 0
        player.lane_idx = player.target_lane = 1
        player.position = (0,0.3,5)
        for e in scene.entities:
            if isinstance(e, (EnemyCar, GoldCoin, StarParticle, ExhaustParticle)):
                destroy(e)
        enemy_timer = coin_timer = 0
        if overlay_text: destroy(overlay_text); overlay_text = None
        return
    if game_over: return
    if key in ('a','left arrow'): player.move_left()
    if key in ('d','right arrow'): player.move_right()

def update():
    global game_over, game_speed, score, enemy_timer, coin_timer, overlay_text
    if game_over: return

    game_speed += speed_increase * time.dt
    spawn_exhaust()

    enemy_timer += time.dt
    if enemy_timer > random.uniform(0.7, 1.3/(game_speed*0.1)):
        spawn_enemy(); enemy_timer = 0
    coin_timer += time.dt
    if coin_timer > random.uniform(1.5, 3.0/(game_speed*0.1)):
        spawn_coin(); coin_timer = 0

    for e in scene.entities:
        if isinstance(e, EnemyCar):
            if abs(e.z - player.z) < 2.2 and abs(e.x - player.x) < 1.2:
                game_over = True
                if not overlay_text:
                    overlay_text = Text("CRASH!\nPress R to restart", position=(0,0.15), scale=3,
                                        color=color.red, origin=(0,0), font='VeraMono.ttf')
                return
        if isinstance(e, GoldCoin):
            if abs(e.z - player.z) < 1.8 and abs(e.x - player.x) < 1.0:
                score += 10
                for _ in range(10): StarParticle(e.world_position, color.gold)
                destroy(e)

    if not hasattr(update, 'hud'):
        update.hud = Text(f"Score: {score}\nSpeed: {game_speed:.1f}", position=(-0.85,0.45), scale=1.5,
                          background=True, color=color.white)
    else:
        update.hud.text = f"Score: {score}\nSpeed: {game_speed:.1f}"

for _ in range(4): spawn_enemy()
for _ in range(6): spawn_coin()

camera.position = (0, 4.5, -10)
camera.rotation_x = 18
camera.look_at((0, 1, 10))

app.run()