例如我当前的角度位置是170,我点击对象将其旋转到-170度,这里的问题是在178,179,180之后,下一个数字是-180,-179,-178和等......
即使在数字上170度仍远离-170度,但在视觉上它们看起来很近,一个物体旋转最长的路径才能达到这个数字,例如:
if(currentAngle < targetAngle)
{
currentAngle += 1;
}
if(currentAngle > targetAngle)
{
currentAngle -= 1;
}
这样我可以达到目标角度,但是如何在180和-180之间跨越这个障碍,也许有一个公式呢?
更新
onclick() {
double angle = Math.atan2(dy, dx);
targetAngle = (int)Math.toDegrees(angle); //180 to //-179
}
onFrame() {
//here happens the animation
if(currentAngle < targetAngle)
{
currentAngle +=1;
}
if(currentAngle > targetAngle)
{
currentAngle -= 1;
}
}
现在如果我现在处于-179角度,我点击160度角度,它应该向左旋转到达那个角度尽可能快,但在我的情况下,它向右旋转(这是更长的),那是因为它被限制在-180到179之间,因此如何突破极限并从179变为-180,-181,-182 ......如果你明白我的意思
1)我的点击处理程序:
onClick() {
double angle = Math.atan2(dy, dx);
angle = (int)Math.toDegrees(angle);
Log.d("test", "angler:" + angle);
if(angle < 0)
angle += 360;
}
所以在这里我使用角度+ = 360将度数转换为正数,然后:
2)我的onFrame处理程序:
onFrame() {
if(currentAngle != angle)
{
if(angle < currentAngle)
{
currentAngle -= 5;
}
else
{
currentAngle += 5;
}
int diff = Math.abs(angle - currentAngle);
if(diff <= 5)
{
currentAngle = angle; // if its near we put it exact to that angle
}
invalidate(); //update the view
}
}
这就是我所拥有的一切
答案 0 :(得分:3)
正如您在问题中定义currentAngle
一样,其值按升序排列:
0,1,2,...,180,-179,-178,...,0
这意味着对你而言,-179大于179,因此算术比较对你不起作用。首先,您必须将这些数字转换为如下所示的范围:
0,1,2,...,180181182,...,359
您可以使用以下公式:
if(angle < 0)
angle += 360
现在你可以找到两个角度之间的区别(比如说angle1
和angle2
):
abs(angle1 - angle2)
或者如果你想越过0,那么这样做:
360 - abs(angle1 - angle2)
为了给你这两个角度之间的最短距离,你可以采取这样的最小距离:
min(abs(angle1 - angle2), 360 - abs(angle1 - angle2))
答案 1 :(得分:1)
请注意,我假设您的角度介于0到359之间,而不是负面。
这里有两个不同的问题。
currentAngle
和targetAngle
,如何确定旋转方向,这将导致以最短帧数完成旋转? 问题1主要在@ ellitron的答案中解决,但你必须将这些部分分开来确定移动currentAngle
的方向。问题2需要一个360的mod,它在每次更新currentAngle
后处理负数,而this answer为我们提供了一个很好的技巧。
if (currentAngle - targetAngle == 0) return;
if (Math.abs(currentAngle - targetAngle) < 180) {
// Rotate current directly towards target.
if (currentAngle < targetAngle) currentAngle++;
else currentAngle--;
} else {
// Rotate the other direction towards target.
if (currentAngle < targetAngle) currentAngle--;
else currentAngle++;
}
currentAngle = ((currentAngle % 360) + 360) % 360;
为了将来参考,以下是如何在渲染环境之外测试此代码的方法。我们可以简单地传入两个命令行参数,并从输出中确定我们是否以正确的方式旋转。
public class Angle {
public static void main(String[] args) {
int currentAngle = Integer.parseInt(args[0]);
int targetAngle = Integer.parseInt(args[1]);
while (currentAngle - targetAngle != 0) {
if (Math.abs(currentAngle - targetAngle) < 180) {
// Rotate current directly towards target.
if (currentAngle < targetAngle) currentAngle++;
else currentAngle--;
} else {
// Rotate the other direction towards target.
if (currentAngle < targetAngle) currentAngle--;
else currentAngle++;
}
currentAngle = ((currentAngle % 360) + 360) % 360;
System.out.printf("CurrentAngle = %d, targetAngle = %d\n",
currentAngle, targetAngle);
}
}
}
答案 2 :(得分:0)
我对旋转动画有同样的问题。从1到-1,它会通过长度为358的大弧,但长度为2的小弧。反之亦然。但是想象一下它得到的值是0、100、200、300、0、100、200、300,依此类推...为了使动画平滑,它必须经过0、100、200、300、360、460的值,560、660,..因此,如果仅顺时针旋转,角度将增加。
查看此算法:
class RotAngle
{
double oldAngle = 0; //old angle modulo 360
int rot = 0; //this is current spin count (times 360 degrees)
public double Rotate(double angle)
{
double currAngle = ((angle % 360) + 360) % 360;
//if you enter only positive angles (angle % 360) will do
//((angle % 360) + 360) % 360 is needed for negative angles
double diff_2 = 2 * (oldAngle - currAngle);
/* mathematically is equal to: old + 360 - current < current - old */
/* so closer is one rotation less */
if (diff_2 < -360) rot--;
/* opposite: 360 + current - old < old - current -> one rotation more is closer */
if (diff_2 > 360) rot++;
oldAngle = currAngle;
return rot * 360 + currAngle;
}
}