Используйте MoveTowards с продолжительностью вместо скорости - PullRequest
0 голосов
/ 04 июля 2018

Я хочу переместить GameObject из положения A в B с помощью Vector3.MoveTowards в течение x секунд и в функции сопрограммы. Я знаю, как сделать это с Vector3.Lerp, но на этот раз я бы предпочел сделать это с Vector3.MoveTowards, поскольку обе функции ведут себя по-разному.

С Vector3.Lerp это делается как this :

IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
    float counter = 0;

    //Get the current position of the object to be moved
    Vector3 startPos = fromPosition.position;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
        yield return null;
    }
}

Я пытался сделать то же самое с Vector3.MoveTowards, но он не работает должным образом. Проблема в том, что движение заканчивается до времени или продолжительности. Кроме того, он не движется плавно. Он переходит на середину обеих позиций, чем на конец позиции B.

Эта функция использует Vector3.MoveTowards с проблемой выше:

IEnumerator MoveTowards(Transform objectToMove, Vector3 toPosition, float duration)
{
    float counter = 0;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        Vector3 currentPos = objectToMove.position;
        float time = Vector3.Distance(currentPos, toPosition) / duration;

        objectToMove.position = Vector3.MoveTowards(currentPos, toPosition,
         time);

        Debug.Log(counter + " / " + duration);
        yield return null;
    }
}

Как вы перемещаете GameObject из положения A в B с помощью Vector3.MoveTowards в течение x секунд и в функции сопрограммы?

Пожалуйста, не предлагайте Vector3.Lerp, поскольку я не хочу этим пользоваться.

EDIT

Замена

float time = Vector3.Distance(currentPos, toPosition) / duration;

с

float time = Vector3.Distance(startPos, toPosition) / (duration * 60f);

работает, но создает проблему, когда фокус переносится с Unity на другое приложение. Это приводит к тому, что движение не заканчивается. Вычислять его каждый кадр вместо одного раза перед запуском таймера кажется более разумным.

Ответ MatrixTai устранил обе проблемы.

1 Ответ

0 голосов
/ 04 июля 2018

Поскольку я долгое время не касался Unity ... но я верю, что вы ошиблись в вычислениях.

Прежде всего, Vector3.MoveTowards(currentPos, toPosition, time) говорит о

Прогулка от currentPos до toPosition с каждым движущимся кадром определенное расстояние time.

Таким образом, использование time в качестве имени сбивает с толку, но хорошо, давайте его сохраним.

Однако, вы заметите в утверждении: time - это что-то, перемещающее каждый кадр. Но Vector3.Distance(currentPos, toPosition) / duration - это скорость (м / с), а не (м / кадр). Чтобы сделать это (м / кадр), просто умножьте на Time.deltatime, то есть (с / кадр).

Во-вторых,

В сопрограмме это означает, что функция повторяется в каждом кадре. В строке float time = Vector3.Distance(currentPos, toPosition) / duration * Time.deltatime; вы заметите, что time продолжает уменьшаться при переходе к следующему кадру, когда расстояние становится все меньше и меньше.

Чтобы быть более конкретным, мы можем сделать немного математики. Как правило, это должно быть сделано с исчислением, но давайте упростим это, рассматривая только 2 пункта. Когда положение объекта d = 0 и положение объекта d ~ = 9,9, предположим, что конечная точка равна 10.

В точке 1 объект имеет time = (10-0) / длительность, полная скорость. В точке 2 объект имеет time = (10-9,9) / длительность, 1/10 от полной скорости.

Если вы не хотите, чтобы он перемещался медленнее в каждом кадре, вы не можете оставить значение длительности без изменений. Как и после каждого кадра, вы хотите, чтобы скорость сохранялась, поэтому продолжительность должна уменьшаться с расстоянием.

Чтобы заставить эту физику работать, минус продолжительность за прошедшее время.

Итак, окончательное решение

float time = Vector3.Distance(currentPos, toPosition) / (duration-counter) * Time.deltaTime;

Вот полная функция:

IEnumerator MoveTowards(Transform objectToMove, Vector3 toPosition, float duration)
{
    float counter = 0;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        Vector3 currentPos = objectToMove.position;

        float time = Vector3.Distance(currentPos, toPosition) / (duration - counter) * Time.deltaTime;

        objectToMove.position = Vector3.MoveTowards(currentPos, toPosition, time);

        Debug.Log(counter + " / " + duration);
        yield return null;
    }
}
...