トリックは、(少なくともユークリッド空間では)角度が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;
これにより、1次元のみで計算を実行しながら、方向を切り替えてもスムーズなモーションが生成されます。さらに、ジョイントの速度と加速度を個別に調整できます。こちらのデモをご覧ください:http : //codepen.io/anon/pen/HGnDF/