from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from math import pi
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3, KeyboardButton, CollisionBox, CollisionSphere, CollisionNode, CollisionTraverser, \
    CollisionHandlerQueue

from panda3d.core import Vec3


class MyApp(ShowBase):
    def __init__(self):
        # -------------ЧТобы мы могли с движком
        ShowBase.__init__(self)  # Python брат , мы теперь иммед доступ к Panda3D
        model_path ="Limoni modelki/Lplace.obj"
        self.lplace = self.loader.loadModel(model_path)
        if self.lplace is None:
            print("Моделька не загружена")
            return
        self.lplace.reparentTo(self.render)
        self.lplace.setScale(10)
        self.lplace.setScale(45, 45, 45)  # менят размер модели ( можно использовать инвертироварование моделей)
        self.lplace.setPos(0, 0, -10)  # изменяет позицию
        self.lplace.setHpr(180, 90, -90)

        model_path = "Limoni modelki/Lemon.obj"
        self.llemon = self.loader.loadModel(model_path)
        if self.llemon is None:
            print("Моделька не загружена")
            return
        self.llemon.reparentTo(self.render)
        self.llemon.setScale(3)
        self.llemon.setPos(0, 10, -1)
        self.llemon.setHpr(90, 90, 90)


        model_path = "Limoni modelki/Ltrain.obj"
        self.ltrain = self.loader.loadModel(model_path)
        if self.ltrain is None:
            print("Моделька не загружена")
            return
        self.ltrain.reparentTo(self.render)
        self.ltrain.setScale(6)
        self.ltrain.setPos(13, 90, -2)
        self.ltrain.setHpr(0,90,0)

        self.x = 0
        self.y = 0
        self.z = 0
        self.keyMap = {
           "up": False,
           "down": False,
           "left": False,
           "right": False,
           "space": False
         }

        self.accept('w', self.updateKey, ["up", True])
        self.accept('w-up', self.updateKey, ["up", False])
        self.accept("s", self.updateKey, ["down", True])
        self.accept("s-up", self.updateKey, ["down", False])
        self.accept('a', self.updateKey, ["left", True])
        self.accept('a-up', self.updateKey, ["left", False])
        self.accept('d', self.updateKey, ["right", True])
        self.accept('d-up', self.updateKey, ["right", False])
        self.accept('space', self.updateKey, ["space", True])
        self.accept('space-up', self.updateKey, ["space", False])

        self.IsGround = True  # Добавлено: Изначально считаем, что на земле
        self.isJumping = False  # Переменная, указывающая, находится ли llemon в прыжке

        self.taskMgr.add(self.update, "update")
        #self.taskMgr.add(self.LTrainMove, "train")
        self.taskMgr.add(self.checkCollision, "checkCollision")

        self.camera.setPos(self.llemon.getX(), self.llemon.getY() - 15, self.llemon.getZ() + 10)
        self.camera.lookAt(self.llemon)

        cs = CollisionSphere(0, 1  , 0, 1)
        box = CollisionBox(2, 2, 2, 2)

        cnodepath = self.llemon.attachNewNode(CollisionNode('Egor'))
        cnodepath.node().addSolid(cs)  # добавляем сферу в нод
        cnodepath.show()  # Показывать коллайдер (для отладки)

        cnodepath2 = self.llemon.attachNewNode(CollisionNode('Oleg'))

        cnodepath2.node().addSolid(box)  # колизия добавляет в панду бокс
        cnodepath2.setPos(self.llemon.getX() - 2, self.llemon.getY() - 10, self.llemon.getZ() - 1)
        cnodepath2.show()

        levelCollider = self.lplace.attachNewNode(CollisionNode('LevelCollider'))  # невидимая коробка для панды
        levelCollider.node().addSolid(CollisionBox((2, 1.2, 2), (6, 1, 6)))  # раземр коробочки (типо растянули)
        levelCollider.setPos(self.llemon.getX() - 4, self.llemon.getY() - 11, self.llemon.getZ() - 3)

        levelCollider.show()

        self.cTrav = CollisionTraverser()  # обработчик столкновений - проверяет, сталкивается ли панда с чем-то
        self.queue = CollisionHandlerQueue()  # сюда записываются столкноения, которые будут обнаружены ударом
        self.cTrav.addCollider(cnodepath, self.queue)

        cnodepath.node().setIntoCollideMask(1)  # 0 - кто толкает, 1 - кто ждет толчка
        cnodepath.node().setFromCollideMask(1)
        levelCollider.node().setIntoCollideMask(1)
        self.jump_height = 2
        self.drop_speed = 0.1

    def updateKey(self, key, status):
        self.keyMap[key] = status

    def update(self, task):
        dt = task.time  # Время, прошедшее с предыдущего кадра
        speed = 0.1  # Скорость движения

        if self.keyMap["up"]:
            self.llemon.setPos(self.llemon.getPos() + Vec3(0, -speed * dt, 0))
        if self.keyMap["down"]:
            self.llemon.setPos(self.llemon.getPos() + Vec3(0, speed * dt, 0))
        if self.keyMap["left"]:
            self.llemon.setPos(self.llemon.getPos() + Vec3(-speed * dt, 0, 0))
        if self.keyMap["right"]:
            self.llemon.setPos(self.llemon.getPos() + Vec3(speed * dt, 0, 0))

        if self.keyMap["space"] and self.IsGround:  # Если пробел нажат и мы на земле
            self.llemon.setPos(self.llemon.getPos() + Vec3(0, 0, 15))  # Поднимаем llemon в воздух
            self.IsGround = False  # llemon больше не на земле
            self.isJumping = True  # llemon начал прыжок

        # Если мы в прыжке (не на земле), опускаемся вниз
        if self.isJumping and not self.IsGround:
            self.llemon.setPos(self.llemon.getPos() + Vec3(0, 0, -self.drop_speed))  # Медленно опускаемся вниз

        # Обновляем камеру
        # self.camera.setPos(self.llemon.getX(), self.llemon.getY() - 15, self.llemon.getZ() + 10)
        # self.camera.lookAt(self.llemon)

        return Task.cont

    def LTrainMove(self, task):
        self.ltrain.setPos(self.ltrain.getPos() + Vec3(-0, 1 / -2, 0))
        if self.ltrain.getPos().y < -125:
            self.ltrain.setPos(13, 90, -2)
        return Task.cont

    def checkCollision(self, task):
        self.cTrav.traverse(self.render)

        for entry in self.queue.getEntries():
            name = entry.getIntoNodePath().getName()
            if name == 'LevelCollider':
                self.IsGround = True
                self.isJumping = False  # Прыжок закончен
                self.llemon.setZ(-1)

        return task.cont

app = MyApp()
app.run()


