RigidBody.MovePosition到达目的地也不会停下来

RigidBody.MovePosition won't stop even after reaching the destination

我正在创建一个不断从 A 点移动到 B 点的电梯。 我不能只使用 transform.position ( location here * speed here etc),因为我有一个带有 Rigidbody 的播放器,如果使用它,每当我在电梯上时,我的播放器就会闪烁。我还尝试在玩家在电梯上时为玩家设置父级(并在它跳跃时取消其父级等),这修复了闪烁,但它在玩家的跳跃机制上有些错误。

最后的手段是使用 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);
}

这会使电梯朝给定的方向移动,但是它没有达到 "reached" 条件。我在那里放置了一个 debug.log 以查看 mpostarget 以查看差异。它以 0, 10, 0 - 0, 10, 0 结尾,这意味着我的目标和电梯的位置已经相同。但是没有达到else条件,电梯一直在B点闪烁

Vector2== operator 使用 0.00001 的估计来实现相等。

然而,您很可能在

中超出了目标
(Vector2)transform.position + direction * _speed * Time.deltaTime

因为你的最终速度speed * Time.deltaTime肯定大于0.00001。 (除了你的 speed 小于 0.0006 我怀疑。)

您在 Debug.Log 中看到的值是 Vector3.ToString 的结果,它使用人类可读的四舍五入值而不显示实际的 float 值!来自 source code

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 来避免这种过度。

Vector3.MoveTowards 的 API 实际上解释得比 Vector2.MoveTowards

更好

Calculate a position between the points specified by current and target, moving no farther than the distance specified by maxDistanceDelta.

Use the MoveTowards member to move an object at the current position toward the target position. By updating an object’s position each frame using the position calculated by this function, you can move it towards the target smoothly. Control the speed of movement with the maxDistanceDelta parameter. If the current position is already closer to the target than maxDistanceDelta, the value returned is equal to target; the new position does not overshoot target. To make sure that object speed is independent of frame rate, multiply the maxDistanceDelta value by 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);
}