诀窍是要记住角度(至少在欧几里得空间中)是周期性的2 * pi。如果当前角度和目标角度之间的差太大(即光标已经越过边界),只需通过相应地加或减2 * pi来调整当前角度。
在这种情况下,您可以尝试以下操作:(我以前从未使用Javascript编程,因此请原谅我的编码风格。)
var dtheta = joint.targetAngle - joint.angle;
if (dtheta > Math.PI) joint.angle += 2*Math.PI;
else if (dtheta < -Math.PI) joint.angle -= 2*Math.PI;
joint.angle += ( joint.targetAngle - joint.angle ) * joint.easing;
编辑:在此实现中,围绕关节中心过快地移动光标会导致其跳动。这是预期的行为,因为关节的角速度始终与成正比dtheta
。如果这种行为是不希望的,则可以通过在接头的角加速度上加一个盖来轻松解决问题。
为此,我们需要跟踪关节的速度并施加最大加速度:
joint = {
// snip
velocity: 0,
maxAccel: 0.01
},
然后,为方便起见,我们将介绍一个裁剪功能:
function clip(x, min, max) {
return x < min ? min : x > max ? max : x
}
现在,我们的移动代码如下所示。首先,我们dtheta
像以前一样进行计算,并joint.angle
根据需要进行调整:
var dtheta = joint.targetAngle - joint.angle;
if (dtheta > Math.PI) joint.angle += 2*Math.PI;
else if (dtheta < -Math.PI) joint.angle -= 2*Math.PI;
然后,我们无需立即移动关节,而是计算目标速度,并使用该速度将clip
其强制在可接受的范围内。
var targetVel = ( joint.targetAngle - joint.angle ) * joint.easing;
joint.velocity = clip(targetVel,
joint.velocity - joint.maxAccel,
joint.velocity + joint.maxAccel);
joint.angle += joint.velocity;
即使仅在切换方向时,也能产生平滑的运动,而仅在一维中执行计算。此外,它允许独立调节关节的速度和加速度。在此处查看演示:http : //codepen.io/anon/pen/HGnDF/