RigidBody.MovePosition не остановится даже после достижения пункта назначения - PullRequest
0 голосов
/ 03 апреля 2020

Я создаю лифт, который постоянно перемещается из точки А в точку Б. Я не могу просто использовать transform.position ( location here * speed here etc), так как у меня есть игрок с Rigidbody, и если я использую его, он будет мерцать моего игрока всякий раз, когда я Я на лифте. Я также пытался воспитывать Игрока, когда он находится на лифте (и отменяет его, когда он прыгает и т. Д. c), что устраняет мерцание, однако это несколько нарушает механизм прыжка игрока.

В крайнем случае используется Rigidbody к моему лифту и перемещает его с этим кодом:

private void FixedUpdate() 
{
    Vector2 l_mypos = new Vector2(transform.position.x, transform.position.y);
    Vector2 l_target = new Vector2(_targetPoint.position.x, _targetPoint.position.y);
    if (l_mypos != l_target)
    {
        MoveElevator(l_target);
        Debug.Log(l_mypos + " - " + l_target);
    }
    else
        Debug.Log("reached");
}

private void MoveElevator(Vector2 toTarget)
{
    Vector2 direction = (toTarget - (Vector2)transform.position).normalized;
    _elevatorRB.MovePosition((Vector2)transform.position + direction * _speed * Time.deltaTime);
}

Это перемещает лифт в указанном направлении, но не достигает "достигнутого" состояния. Я разместил debug.log там, чтобы увидеть и mpos, и target, чтобы увидеть различия. Он заканчивается знаком 0, 10, 0 - 0, 10, 0, означающим, что и моя цель, и положение лифта уже совпадают. Однако это не достигает другого условия, и лифт продолжает мигать в точке B.

1 Ответ

2 голосов
/ 03 апреля 2020

Оператор == для Vector2 использует оценку 0.00001 для равенства.

Однако вполне возможно, что вы превысили цель в

(Vector2)transform.position + direction * _speed * Time.deltaTime

, поскольку ваша конечная скорость speed * Time.deltaTime определенно больше, чем 0.00001. (За исключением того, что ваш speed меньше 0.0006, в чем я сомневаюсь.)

Значение, которое вы видите в Debug.Log, является результатом Vector3.ToString, который использует читаемые человеком округленные значения и не показывает на самом деле float значения! Из исходного кода

public override string ToString()
{
    return ToString(null, CultureInfo.InvariantCulture.NumberFormat);
}

public string ToString(string format)
{
    return ToString(format, CultureInfo.InvariantCulture.NumberFormat);
}

public string ToString(string format, IFormatProvider formatProvider)
{
    if (string.IsNullOrEmpty(format)) format = "F1"; // <- !! HERE !!

    return UnityString.Format("({0}, {1}, {2})", x.ToString(format, formatProvider), y.ToString(format, formatProvider), z.ToString(format, formatProvider));
}

Вы должны использовать Vector2.MoveTowards, чтобы избежать этого превышения.

API Vector3.MoveTowards на самом деле объясняет это лучше, чем один из Vector2.MoveTowards

Рассчитать позицию между точками, указанными в current и target, не двигаясь дальше расстояния определяется maxDistanceDelta.

. Используйте элемент MoveTowards, чтобы переместить объект в положение current в направлении положения target. Обновляя положение объекта в каждом кадре, используя положение, рассчитанное этой функцией, вы можете плавно перемещать его к цели. Управляйте скоростью движения с помощью параметра maxDistanceDelta. Если позиция current уже ближе к target, чем maxDistanceDelta, возвращаемое значение равно target; новая позиция не выходит за пределы цели . Чтобы убедиться, что скорость объекта не зависит от частоты кадров, умножьте значение maxDistanceDelta на Time.deltaTime

private void FixedUpdate() 
{
     // Vector3 and Vector2 have implicit operators allowing to use
     // both types exchangeably. 
     // In order actively to convert them you can simply typecast between them
     var l_mypos = (Vector2) transform.position;
     var l_target = (Vector2) _targetPoint.position;

     if (l_mypos != l_target)
     {
         MoveElevator(l_target);
         Debug.Log(l_mypos + " - " + l_target);
     }
     else
     {
         Debug.Log("reached");
     }
}

private void MoveElevator(Vector2 toTarget)
{
    var pos = Vector2.MoveTowards(transform.position, toTarget, _speed * Time.deltaTime);
    _elevatorRB.MovePosition(pos);
}
...