【发布时间】:2012-06-04 22:01:25
【问题描述】:
情况
我一直在思考这个问题有一段时间了。基本上,我有一个角度r (弧度),我想将其更改为所需的角度wr (弧度) em> 在模拟的每个步骤中,以设定的速度dr (弧度/秒)。因此,我需要对于每一步,我都有一个新角度 nr,其中 nr = r + dr * dt 和 dt 是增量时间从上一步开始。
角度在空间 [-pi, pi] 中,增量角度由最短的转弯方式决定。对于每一步,增量角度都被添加到当前旋转中,包裹到 [-pi, pi] 并存储为新角度。
由于我的步数没有无限精确,我显然 - 实际上 - 永远不会直接达到所需的角度,因此我需要找到达到所需旋转的时间 - 并越过 - 然后停止旋转并将角度设置为所需的角度。在伪代码中:
if rotationSpeed!= 0
angle = WrapRotation(angle + rotationSpeed * deltaTime)
if desiredAngle has been reached or crossed
angle = desiredAngle
rotationSpeed = 0
问题
在几乎所有情况下,这都很容易做到,但是当你的角度足够高或足够低(接近 -pi 或 pi)并且新角度带你越过“边界”时,可以这么说,事情变得复杂的。我所有的尝试都未能涵盖当前、先前和所需轮换的所有可能情况。所以我问你是否碰巧知道解决方案?
如果需要,我在下面附上了我的代码 (C#):
// Sets the desired rotation and rotation speed in radians/second:
public void SetRotation(float rotation, float speed)
{
desiredRotation = MathHelper.WrapAngle(rotation);
if (desiredRotation != this.rotation)
{
// Determine the shortest way to turn (indicated by the sign of speed)
float a = desiredRotation - this.rotation;
if (a > Math.PI) a -= 2 * (float)Math.PI;
if (a < -Math.PI) a += 2 * (float)Math.PI;
desiredRotationSpeed = a < 0 ? -speed : speed;
}
}
// Update is called per each step. Takes in the amount of seconds since the last call.
public void Update(float seconds)
{
/* Other stuff */
if (desiredRotationSpeed != 0)
{
float delta = desiredRotationSpeed * seconds;
rotation = MathHelper.WrapAngle(rotation + delta);
if( /* This is the part I'm struggling with. */ )
{
desiredRotationSpeed = 0f;
rotation = desiredRotation;
}
}
/* Other stuff */
}
在正常情况下(非循环行为),以下工作:
if (Math.Abs(value - desiredValue) < Math.Abs(deltaValue))
/* Desired has been reached. Do stuff! */
所以澄清一下。我想知道何时达到了所需的角度(并且由于精度而超过了),以便我可以将当前角度设置为所需的角度,并停止旋转。
非常感谢您的帮助!我有一种感觉,这真的有一个简单的解决方案! :3
【问题讨论】:
-
你能用“角度”这个词代替“旋转”吗?当您使用“旋转”时,听起来您在谈论动词名称,而不是角度。哦,顺便说一句,这很重要,您的相等性检查需要自定义,以便您可以自己设置所需的准确性等。否则你可能永远不会达到停止条件。或者我只是对你想要做什么感到困惑。对不起。
-
确实如此。现在将它们中的许多更改为角度并保持旋转以进行旋转动作。此外,这正是我想要帮助的。我真的不知道如何检测由于旋转的循环性质而发生的停止条件。边界 -pi/pi 对我来说是令人困惑的。我计算每一步的新角度,并且需要确定我是否已经越过(或达到)所需的角度。对不起,我只是觉得这个很难解释! :)