import random
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController

app = Ursina()

Sky()

# 小地图, 在屏幕左上角
minimap = Entity(model='quad', scale=(0.3, 0.3), texture='grass', color=color.rgba(255, 255, 255, 200), parent=camera.ui, position=(-0.68, 0.3, 0))

# 创建地面
land = Entity(model='plane', texture='grass', scale=(800, 1, 800), collider='box')

# 玩家蛇
player_snake = FirstPersonController(model='cube', speed=50, jump_height=0, collider='box')  # 保持 box 碰撞框

# 小地图上的蛇位置指示器
minimap_dot = Entity(
    parent=minimap,  # 作为小地图的子对象
    model='circle', 
    color=color.red, 
    scale=0.05,  # 小圆点的大小
    position=(0, 0, 0)  # 初始位置在小地图中心
)

class Snake():
    def __init__(self):
        self.length = 0
        self.jump_height = 0
    
    def update(self):
        self.check_collisions()
        self.move_f()
        self.update_minimap()  # 更新小地图
    
    def eat_food(self, food):
        self.grow()
        food.disable()  # 禁用食物
        # player_snake.speed += 0.03
        self.length += 1

    def move_f(self):
        # 往面向的方向走一步
        player_snake.position += player_snake.forward * player_snake.speed * time.dt
    
    def grow(self):
        # player_snake.scale += (0.1, 0.1, 0.1)
        bodys.append(Body(self.length))
    
    def update_minimap(self):
        
        # 计算归一化位置 (0到1之间)
        norm_x = (player_snake.x + 400) / 800
        norm_z = (player_snake.z + 400) / 800
        
        # 映射到小地图坐标系 (原点在中心)
        minimap_x = (norm_x - 0.5)  # 范围[-0.5, 0.5]
        minimap_y = (norm_z - 0.5)  # 范围[-0.5, 0.5]
        
        # 更新小圆点位置
        minimap_dot.position = (minimap_x, minimap_y)
        minimap_dot.scale = (0.05, 0.05, 0.05)

    def check_collisions(self):
        for food in foods:
            # 检查蛇与食物是否碰撞
            if player_snake.intersects(food).hit:
                self.eat_food(food)
                foods.remove(food)  # 从食物列表中移除
                foods.append(Food())

class Body(Entity):
    def __init__(self, index):
        super().__init__(model='body.glb')
        self.scale = (player_snake.scale[0] * 3, player_snake.scale[1] * 3, player_snake.scale[2] * 3)
        self.index = index
        self.minimap_dot = Entity(
            parent=minimap,  # 作为小地图的子对象
            model='circle', 
            color=color.green, 
            scale=0.05,  # 小圆点的大小
            position=(0, 0, 0)  # 初始位置在小地图中心
        )

    def update(self):
        self.position = position_list[self.index]
        self.update_minimap()

    def update_minimap(self):
        # 计算归一化位置 (0到1之间)
        norm_x = (self.x + 400) / 800
        norm_z = (self.z + 400) / 800
        
        # 映射到小地图坐标系 (原点在中心)
        minimap_x = (norm_x - 0.5)  # 范围[-0.5, 0.5]
        minimap_y = (norm_z - 0.5)  # 范围[-0.5, 0.5]
        
        # 更新小圆点位置
        self.minimap_dot.position = (minimap_x, minimap_y)
        self.minimap_dot.scale = (0.05, 0.05, 0.05)

class Food(Entity):
    def __init__(self):
        super().__init__(model='food.glb', scale=8, collider='box', is_trigger=True)  # 设置 is_trigger 为 True
        self.x = random.randint(-400, 400)
        self.z = random.randint(-400, 400)
        self.position = Vec3(self.x, 0.5, self.z)
        self.minimap_dot = Entity(
            parent=minimap,  # 作为小地图的子对象
            model='circle', 
            color=color.blue, 
            scale=0.05,  # 小圆点的大小
            position=(0, 0, 0)  # 初始位置在小地图中心
        )

    def update(self):
        self.update_minimap()

    def update_minimap(self):
        # 计算归一化位置 (0到1之间)
        norm_x = (self.x + 400) / 800
        norm_z = (self.z + 400) / 800
        
        # 映射到小地图坐标系 (原点在中心)
        minimap_x = (norm_x - 0.5)  # 范围[-0.5, 0.5]
        minimap_y = (norm_z - 0.5)  # 范围[-0.5, 0.5]
        
        # 更新小圆点位置
        self.minimap_dot.position = (minimap_x, minimap_y)
        self.minimap_dot.scale = (0.03, 0.03, 0.03)

# 创建多个食物
foods = [Food() for _ in range(800)]

bodys = []

position_list = [0]

# 创建蛇
snake = Snake()

def update():
    snake.update()

    for i in range(len(position_list) - snake.length):
        position_list.remove(position_list[i])

    position_list.append(player_snake.position)

    for food in foods:
        food.update()

    for body in bodys:
        body.update()

app.run()