【问题标题】:RigidBody.MovePosition won't stop even after reaching the destinationRigidBody.MovePosition 即使到达目的地也不会停止
【发布时间】:2020-04-03 07:03:55
【问题描述】:

我正在创建一个电梯,它不断地从 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);
}

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

【问题讨论】:

    标签: unity3d physics rigid-bodies


    【解决方案1】:

    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 的 API 解释得更好

    计算currenttarget 指定的点之间的位置,移动不超过maxDistanceDelta 指定的距离。

    使用MoveTowards 成员将current 位置的对象移向target 位置。通过使用此函数计算的位置在每一帧更新对象的位置,您可以将其平滑地移向目标。使用maxDistanceDelta 参数控制移动速度。如果current位置已经比maxDistanceDelta更接近target,则返回值等于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);
    }
    

    【讨论】:

    • 感谢您的回答。我也学到了一些东西:)
    • 我已经使用刚体和刚体.MoveTowards 解决了这个问题。但是非常感谢您的回答,它仍然非常有用! :)
    猜你喜欢
    • 1970-01-01
    • 2011-02-01
    • 2015-10-23
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 2023-03-25
    • 1970-01-01
    相关资源
    最近更新 更多