角度边界问题

发布于 2024-11-24 05:24:51 字数 1212 浏览 0 评论 0原文

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

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

我检查使用

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

where

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;            
            }
        }

Heads up: Even though this problem arose while I was working with Unity, it has nothing specific to Unity, and is more about programming logic, so please don't shy away.

I'm using Unity and rotating an object by script. The thing is, if I rotate it to, say, 180 degrees, the object does not rotate exactly to that much and tends to stop at between 179 and 181 degrees. So, to check if rotation is complete I check if the rotation angle is targetAngle +/- 1, which works.

I check using

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

where

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

Now, the problem arises when the targetAngle is 0. In this case, my script checks if rotation angle is between -1 and 1. But, -1 should really be 359, so it needs to check if the angle lies between 359 and 1.

How can I implement this?
In other words, I guess I'm asking how to implement a wrap-around number system.

EDIT

Found one work-around. If targetAngle is 0, I treat is specially. It works, but isn't the most elegant.

         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;            
            }
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瑾夏年华 2024-12-01 05:24:52

您可以这样做...

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)

根据您需要使用此功能的频率,检查某些情况可能会消除不必要的开销。例如,仅当输入为正时才需要wrappNumber 中的最后一个% 360。如果您每分钟调用此命令十次,那可能并不重要。如果您每秒调用它一百次,您可能需要检查它在这种情况下的执行情况。

You could do ...

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)

This moves the check away from the zero and you wouldn't have to deal with positive/negative checking.

EDIT

The % operator on the targetAngle restricts the rotating to +/-359 degrees, so a target angle of 721 would come down to 1, and a target angle of -359 would come down to 1. This should do nicely for all cases I think.

EDIT 2

To fix the last case you mentioned in your comment, I guess you'd need to apply the same wrapping logic to your transform.eulerAngles.z values. Probably best to put this wrapping in an extra function now, so try this:

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)

Depending on how often you need to use this, checking for some cases might remove unneeded overhead. For example, the final % 360 within wrapNumber is only needed if the input was positive. If you're calling this ten times per minute it probably won't matter. If you're calling it a hundred times per second, you may want to check how it performs in this situation.

卸妝后依然美 2024-12-01 05:24:52

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

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

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

This may be an old thread but after looking at many different snippets all trying to deal with Wrapping I found that Unity has a nice builtin function that simply takes care of business, At least in my case that the end result i required was a lerp so i only had to change it to LerpAngle and it returned a solid result.

Mathf.LerpAngle is your friend.. solved all my issues with popping etc..

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文