O truque é lembrar que os ângulos (pelo menos no espaço euclidiano) são periódicos em 2 * pi. Se a diferença entre o ângulo atual e o ângulo alvo for muito grande (ou seja, o cursor cruzou o limite), basta ajustar o ângulo atual adicionando ou subtraindo 2 * pi de acordo.
Nesse caso, você pode tentar o seguinte: (nunca havia programado em Javascript antes, perdoe meu estilo de codificação.)
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;
EDIT : Nesta implementação, mover o cursor muito rapidamente ao redor do centro da articulação faz com que ele se solte. Este é o comportamento pretendido, uma vez que a velocidade angular da articulação é sempre proporcional a dtheta
. Se esse comportamento for indesejável, o problema pode ser facilmente resolvido colocando uma tampa na aceleração angular da articulação.
Para fazer isso, precisamos acompanhar a velocidade da articulação e impor uma aceleração máxima:
joint = {
// snip
velocity: 0,
maxAccel: 0.01
},
Em seguida, para nossa conveniência, apresentaremos uma função de recorte:
function clip(x, min, max) {
return x < min ? min : x > max ? max : x
}
Agora, nosso código de movimento se parece com isso. Primeiro, calculamos dtheta
como antes, ajustando joint.angle
conforme necessário:
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;
Em seguida, em vez de mover a articulação imediatamente, calculamos uma velocidade alvo e a usamos clip
para forçá-la dentro de nossa faixa aceitável.
var targetVel = ( joint.targetAngle - joint.angle ) * joint.easing;
joint.velocity = clip(targetVel,
joint.velocity - joint.maxAccel,
joint.velocity + joint.maxAccel);
joint.angle += joint.velocity;
Isso produz movimento suave, mesmo ao mudar de direção, enquanto realiza cálculos em apenas uma dimensão. Além disso, permite que a velocidade e a aceleração da junta sejam ajustadas independentemente. Veja a demonstração aqui: http://codepen.io/anon/pen/HGnDF/