【问题标题】:Problem with bounds of an angle角度范围问题
【发布时间】:2011-07-17 10:09:14
【问题描述】:

请注意:尽管这个问题是在我使用 Unity 时出现的,但它与 Unity 无关,更多的是关于编程逻辑,所以请不要回避。

我正在使用 Unity 并通过脚本旋转对象。问题是,如果我将它旋转到 180 度,则对象不会完全旋转到那么多,并且往往会停在 179 到 181 度之间。因此,为了检查旋转是否完成,我检查旋转角度是否为 targetAngle +/- 1,这可行。

我检查使用

if (transform.eulerAngles.z > lowerLimit && transform.eulerAngles.z < upperLimit)

在哪里

lowerLimit = targetAngle-1;
upperLimit = targetAngle + 1;

现在,当 targetAngle 为 0 时出现问题。在这种情况下,我的脚本检查旋转角度是否在 -1 和 1 之间。但是,-1 应该是 359,所以它需要检查角度是否介于359 和 1。

我该如何实现呢? 换句话说,我想我是在问如何实现一个环绕数字系统。

编辑

找到一种解决方法。如果targetAngle为0,我对待是特殊的。它有效,但不是最优雅的。

         if (targetAngle == 0.0)
        {
            if ((transform.eulerAngles.z > 359.0 && transform.eulerAngles.z <= 360.0) || (transform.eulerAngles.z >= 0.0 && transform.eulerAngles.z <= 1)) 
            {
                rotate = false;            
            }
        }
        else
        {
            if (transform.eulerAngles.z > targetAngle - 1 && transform.eulerAngles.z < targetAngle + 1)
            {
                rotate = false;            
            }
        }

【问题讨论】:

    标签: c# unity3d euler-angles


    【解决方案1】:

    你可以...

    lowerLimit = (targetAngle % 360) + 359; //360 - 1;
    upperLimit = (targetAngle % 360) + 361; //360 + 1;
    
    if (((transform.eulerAngles.z + 360) % 360) > lowerLimit
     && ((transform.eulerAngles.z + 360) % 360) < upperLimit)
    

    这会使检查远离零,您不必处理正/负检查。

    编辑

    targetAngle 上的 % 运算符将旋转限制为 +/-359 度,因此 721 的目标角度将降至 1,而 -359 的目标角度将降至 1。这应该在我认为的所有情况下都做得很好。

    编辑 2

    要解决您在评论中提到的最后一种情况,我想您需要将相同的包装逻辑应用于您的 transform.eulerAngles.z 值。现在最好把这个包装放在一个额外的函数中,所以试试这个:

    int wrapNumber(int input) // replace int with whatever your type is
    {
      // this will always return an angle between 0 and 360:
      // the inner % 360 restricts everything to +/- 360
      // +360 moves negative values to the positive range, and positive ones to > 360
      // the final % 360 caps everything to 0...360
      return ((input % 360) + 360) % 360;
    }
    
    lowerLimit = wrapNumber(targetAngle) + 359; //360 - 1;
    upperLimit = wrapNumber(targetAngle) + 361; //360 + 1;
    
    if (wrapNumber(transform.eulerAngles.z) + 360 > lowerLimit
     && wrapNumber(transform.eulerAngles.z) + 360 < upperLimit)
    

    根据您需要使用它的频率,检查某些情况可能会消除不必要的开销。例如,仅当输入为正时才需要 wrapNumber 中的最后一个 % 360。如果您每分钟调用十次,则可能无关紧要。如果你每秒调用它一百次,你可能想检查它在这种情况下的表现。

    【讨论】:

    • 啊,非常好。在这种特定情况下,我永远不需要旋转超过 180,所以我想我会使用它。谢谢!
    • 我仍然遇到一个问题。如果 targetAngle 为 0,lowerLimit 为 359,upperLimit 为 361。但是当从 180 旋转到 0(与 360 相同)时,旋转停止在 359 左右。所以,在这种情况下,我正在检查是否 ((359+360) > 359 && (359+360)
    • 请尝试最后一次编辑。我 100% 确定这可以通过巧妙地使用模数并根据需要添加 360 来解决。如果这仍然不是,恐怕我可能需要在调试环境中看到它才能完全确定它。既然我现在得走了,如果你发布你的进度,我今晚或明天再看一次(除非你或其他人到那时修复它)。
    【解决方案2】:

    这可能是一个旧线程,但是在查看了许多尝试处理 Wrapping 的不同 sn-ps 之后,我发现 Unity 有一个很好的内置函数,可以简单地处理业务,至少在我的情况下,最终结果是required 是一个 lerp,所以我只需将其更改为 LerpAngle 即可返回可靠的结果。

    Mathf.LerpAngle 是你的朋友。解决了我所有的弹出等问题。

    http://docs.unity3d.com/ScriptReference/Mathf.LerpAngle.html

    【讨论】: