Получение yaw игрока через lastTick координату и которая на данный момент

Версия Minecraft
1.12.2
27
2
2
Приветствую, крч сижу и ломаю голову как это можно сделать. Попробовал пару вариантов, нихера не получилось.

Кто не понял, что надо: У игрока есть координаты с прошлого тика и координаты на которых он находится на данный момент.
К примеру posX и lastTickPosX
С помощью них мне нужно понять, по какому яву можно двигаться примерно в том же направлении что и игрок, только уже по прямой.
Т.е игрок зажимает w и d он идёт наискосок, и код должен высчитать какой yaw нужно поставить чтобы можно было идти в том же направлении только зажав W, и всё.

Надеюсь понятно, если у кого ещё остались вопросы, то пишите.
Буду рад любой помощи или объяснению.
 
Решение
По факту даже мне пришлось перечитать пояснение выше несколько раз, прежде чем я понял весь смысл. Ну да не суть.
Как-то так может выглядеть конкретный код рассчётов:
Java:
    public float getYawFromMotion(EntityPlayer player) {
        // Вектор движения игрока в трёх измерениях
        Vec3d motionVec = new Vec3d(player.posX - player.lastTickPosX, player.posY - player.lastTickPosY, player.posZ - player.lastTickPosZ).normalize();

        return this.getYaw(motionVec);
    }

    private float getYaw(Vec3d motionVec) {
        // Забываем Y, он нам не пригодится
        motionVec = new Vec3d(motionVec.x, 0, motionVec.z);

        if (motionVec.x == 0 && motionVec.z == 0)
            return 0F; // Надо думать, игрок не двигается по...
Я смогу дать более развёрнутый ответ завтра, но вот краткий вариант на случай, если разберёшься с деталями сам.

Для начала тебе нужно вычислить вектор движения, взяв текущие x/y/z игрока и отняв от них таковые с предыдущего тика. Всё это заворачиваешь в векторный объект для упрощения дальнейших манипуляций, я бы рекомендовал реализацию Vector3 из ботании, но и ванильный Vec3d сгодится. Нормализируешь и получаешь направление движение игрока, но пока во всех трёх измерениях. Чтобы получить чистую горизонталь, обнуляешь Y и ещё раз нормализируешь.
А дальше самое весёлое - разобраться, как этот вектор соотнести с yaw. Для этого надо понять как соотносится вектор взгляда игрока, получить который можно вызвав getLookVec() на самом игроке, с его переменной yaw. Если ты достаточно умён и сообразителен, сможешь вывести формулу преобразования сам, покопавшись в ванилла коде и малость подебажив.
 
Я смогу дать более развёрнутый ответ завтра, но вот краткий вариант на случай, если разберёшься с деталями сам.

Для начала тебе нужно вычислить вектор движения, взяв текущие x/y/z игрока и отняв от них таковые с предыдущего тика. Всё это заворачиваешь в векторный объект для упрощения дальнейших манипуляций, я бы рекомендовал реализацию Vector3 из ботании, но и ванильный Vec3d сгодится. Нормализируешь и получаешь направление движение игрока, но пока во всех трёх измерениях. Чтобы получить чистую горизонталь, обнуляешь Y и ещё раз нормализируешь.
А дальше самое весёлое - разобраться, как этот вектор соотнести с yaw. Для этого надо понять как соотносится вектор взгляда игрока, получить который можно вызвав getLookVec() на самом игроке, с его переменной yaw. Если ты достаточно умён и сообразителен, сможешь вывести формулу преобразования сам, покопавшись в ванилла коде и малость подебажив.
Попытаюсь, конечно, же, но не могу дать 100%, что пойму всё сам. С расчётами у меня всё плохо, я могу понять суть кода, но если там будут жесткие формулы, я буду искать обходной вариант. Его кстати я его уже нашёл, но это по сути костыль, если сможешь помочь или я сам пойму как эт сделать конечно же перепишу его XD
 
Мне кажется вы решаете задачу не от того конца, вы хотите проверить правильное ли расстояние прошел игрок? спидхак?
Vector3 vec = new Vector3(currectX - newX, 0, currentZ - newZ); if( Math.abs(vec.len()) >= ... ) // - длинна пройденного пути, Vector3 (libgdx API)

А вообще угол находится так

Угол между двумя точками:
Vector3 vec1 = new Vector3(currentX, 0, currentZ).nor();
Vector3 vec2 = new Vector3(newX, 0, newZ).nor();

float angle = (MathUtils.atan2(vec1.z, vec1.x) - MathUtils.atan2(vec2.z, vec2.x));
angle *= MathUtils.radiansToDegrees;
System.out.println(angle); // 0.0 - 180.0
 
Последнее редактирование:
Мне кажется вы решаете задачу не от того конца, вы хотите проверить правильное ли расстояние прошел игрок? спидхак?
Нет.
А вообще угол находится так
По сути уже, чтото верное, но я проверил данный код и он особо не воркает.

Попробую объяснить вам ещё раз.
У объекта игрока есть несколько переменных на координаты, на прошлый тик и на сейчашний.
lastTickPos(X/Y/Z) и pos(X/Y/Z)
Мы берём от туда только X и Z
К примеру у lastTickPos получились координаты: 5 0 5
А у pos получились координаты: 6 0 5
В таком случае код должен выдать yaw игрока = -90
Т.е код выдает просто тот yaw по которому ты можешь смотреть и двигаться в том же направление.
Надеюсь сейчас вам понятна суть чего я хочу.
 
Надеюсь сейчас вам понятна суть чего я хочу.
она изначально понятна. Какой угол выдаёт при таких параметрах? Это угол между точками, относительно горизонта. А вот куда его довернуть Вам и надо определить.
Соответственно это определяется УГЛОМ направление игрока (или те же самые 2 вектора. Один это где стоит игрок, второй куда он смотрит). Допустим мы смотрим строго вперёд и этот угол равен 90 градусов. А куда он дошел, 10 градусов. Значит надо из 90 вычесть 10 и получим 80 по часовой (CWW). То есть, если вернуть его обратно и повернуть на 80 градусов по часовой и пройти длину пути (расстояние между векторами старой и новой точки), то мы должны оказаться почти в том же самом месте (плюс минут там 1/1000 или 1/10000).
1630076931299.png
Понятно?

То есть тут ещё надо определить в какую сторону довернуть (по часовой CWW или против часовой CW).
Кроме того, ещё нужно будет потом вычесть из полученных координат те что имеем и сравнить длину, что она не превышает 1/1000)
 
Последнее редактирование:
По факту даже мне пришлось перечитать пояснение выше несколько раз, прежде чем я понял весь смысл. Ну да не суть.
Как-то так может выглядеть конкретный код рассчётов:
Java:
    public float getYawFromMotion(EntityPlayer player) {
        // Вектор движения игрока в трёх измерениях
        Vec3d motionVec = new Vec3d(player.posX - player.lastTickPosX, player.posY - player.lastTickPosY, player.posZ - player.lastTickPosZ).normalize();

        return this.getYaw(motionVec);
    }

    private float getYaw(Vec3d motionVec) {
        // Забываем Y, он нам не пригодится
        motionVec = new Vec3d(motionVec.x, 0, motionVec.z);

        if (motionVec.x == 0 && motionVec.z == 0)
            return 0F; // Надо думать, игрок не двигается по горизонтали

        motionVec = motionVec.normalize();

        // Базовый вектор, от которого мы считаем градусы
        // На самом деле он не сильно нужен, но так выглядит понятнее
        Vec3d base = new Vec3d(0, 0, 1);

        double dx = motionVec.x - base.x;
        double dz = motionVec.z - base.z;

        // Получаем угол между векторами в радианах
        double angle = Math.atan2(dz, dx);

        // Переводим в градусы, и множим на два потому что причины
        return (float) Math.toDegrees(angle) * 2;
    }
Прими во внимание, что lastTickPos существует только на клиентской стороне. Если тебе нужны эти данные на сервере, придётся пересылать их пакетом, ну или уже непосредственный результат рассчётов.

И да, это не самое оптимальное исполнение, здесь есть несколько ненужных действий. Фокус больше на человекочитабельности и ментальной визуализируемости происходящего в коде.
 
По факту даже мне пришлось перечитать пояснение выше несколько раз, прежде чем я понял весь смысл. Ну да не суть.
Как-то так может выглядеть конкретный код рассчётов:
Java:
    public float getYawFromMotion(EntityPlayer player) {
        // Вектор движения игрока в трёх измерениях
        Vec3d motionVec = new Vec3d(player.posX - player.lastTickPosX, player.posY - player.lastTickPosY, player.posZ - player.lastTickPosZ).normalize();

        return this.getYaw(motionVec);
    }

    private float getYaw(Vec3d motionVec) {
        // Забываем Y, он нам не пригодится
        motionVec = new Vec3d(motionVec.x, 0, motionVec.z);

        if (motionVec.x == 0 && motionVec.z == 0)
            return 0F; // Надо думать, игрок не двигается по горизонтали

        motionVec = motionVec.normalize();

        // Базовый вектор, от которого мы считаем градусы
        // На самом деле он не сильно нужен, но так выглядит понятнее
        Vec3d base = new Vec3d(0, 0, 1);

        double dx = motionVec.x - base.x;
        double dz = motionVec.z - base.z;

        // Получаем угол между векторами в радианах
        double angle = Math.atan2(dz, dx);

        // Переводим в градусы, и множим на два потому что причины
        return (float) Math.toDegrees(angle) * 2;
    }
Прими во внимание, что lastTickPos существует только на клиентской стороне. Если тебе нужны эти данные на сервере, придётся пересылать их пакетом, ну или уже непосредственный результат рассчётов.

И да, это не самое оптимальное исполнение, здесь есть несколько ненужных действий. Фокус больше на человекочитабельности и ментальной визуализируемости происходящего в коде.
Спасибо огромное, что помог мне с этим и дополнительно ещё комментарии добавил, это помогло мне чисто разобраться в этом. Благодарю также @ZZZubec, тоже дал довольно хорошее объяснение.

Спасибо вам!
 
Назад
Сверху