使用atan2制作角度动画

3
var diffx = (this.destination.x - pos.x), px = diffx / dist;
var diffy = (this.destination.y - pos.y), py = diffy / dist;
var angle = Math.atan2(diffy, diffx) - rot.z;

rot.set(0, 0, rot.z + angle / 24);

一个物体指向我的鼠标光标。我使用上面的代码来计算角度(弧度制)并在几个帧之内“动画”角度。然而,当angle变量从正数变为负数(在PI弧度处),它会顺时针旋转到新鼠标位置(如红色所示)。然而,我期望的路径是直接到达新角度(绿色箭头)。
编辑:
这就是我想出来的解决方法,似乎有效。我能做得更好吗?
            if(atan - this.lastAtan < -Math.PI)
                atan += Math.PI * 2;
            else if(atan - this.lastAtan > Math.PI)
                atan -= Math.PI * 2;
            this.lastAtan = atan;

            var zrot = rot.z + (atan * 12 * Game.dt);
            rot.set(0, 0, zrot % (Math.PI * 2));
1个回答

3

需要考虑到atan2输出的范围只在-π到+π之间。如果atan2输出与上次角度的差大于π,则说明发生了一些环绕,需要通过加/减2*pi进行校正。


第一次旋转时运行良好,但第二次旋转时出现相同的问题。我猜想我必须根据我已经完成的旋转次数不断添加/减去2pi。 - John
1
你可以使用取模运算符来避免重复的加法/减法 - https://dev59.com/FGQn5IYBdhLWcg3w36XV。 - Jack Whitham
谢谢,我已经让它工作了。我把它添加到了原始帖子中,我能简化它吗? - John
取模运算符在这种情况下可能是多余的。我认为你有一个很好的解决方案,不需要它。在“if”语句之后分配 this.lastAtan = atan 才是真正使其工作的关键。 - Jack Whitham
我确实需要它,但解释起来很复杂。如果没有它,对象将再次解开。if(atan - this.lastAtan < -Math.PI) 只对一次旋转成立,因为我只执行了 atan += Math.PI * 2; 一次。在我的当前解决方案之前,我尝试使用一个名为 rotations 的内部变量,并记录它穿过边界的次数,并每次旋转时添加2pi。然而,我的当前方法不需要内部状态。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接