0

計算された 2 つの点の間でキャンバスの周りのオブジェクトをアニメーション化しようとしています。ただし、私が使用している方法では、ポイント間の距離が考慮されていないようです。たとえば、遠距離と短距離のアニメートにかかる時間は同じです。

一定の速度でオブジェクトをアニメーション化するための最良の方法は何ですか?

/**
 * Update function that is called in a setInterval. Moves boid to a new position
 *
 **/
this.update = function(){
    context.clearRect(0,0,canvas.width,canvas.height);


    this.amount += 0.005;
    if (this.amount > 1) this.kill();

    this.x = this.origX + (this.destX - this.origX) * this.amount;
    this.y = this.origY + (this.destY - this.origY) * this.amount;

    this.drawBoid();

    //console.log(this.x + ' ' + this.y);




}
4

2 に答える 2

3

最後のフレームからの経過時間と、アニメートする速度(単位時間あたりの距離単位) に基づいてアニメートするアプローチを取ることをお勧めします。

経過時間を計算するときは、十分に注意する必要があります。setIntervalミリ秒ごとに起動するようにスケジュールしたからといっnて、コードが正確にその時間に起動するわけではありません。さらに悪いことにsetInterval、最低でも 4 ミリ秒の遅延があります。本当に!代わりに、コードの実行時のクロックに依存してください。

さらに良いことに、最新のブラウザーにはrequestAnimationFrame()、再描画が発生するたびにコードのチャンクを呼び出すというメソッドがあります。コールバックを渡すと、タイムスタンプを最初の引数としてそのメソッドを呼び出します。

// Find your browser's implementation of requestAnimationFrame
window.requestAnimationFrame =
  window.requestAnimationFrame || 
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame || 
  window.msRequestAnimationFrame;

// The update method
var update = function(timestamp) {
  context.clearRect(0, 0, canvas.width, canvas.height);

  // How much time has elapsed since the start of the animation?
  var elapsedTime = timestamp - startTime;

  // How far have we moved at that time?
  var distanceTravelled = elapsedTime * speed;
  if (distanceTravelled >= totalDistance) distanceTravelled = totalDistance; // Don't overshoot

  // How far have we moved in each component?
  var distanceTravelledX = xPerUnitDistance * distanceTravelled;
  var distanceTravelledY = yPerUnitDistance * distanceTravelled;

  // Move there!
  this.x = Math.round(origin.x + distanceTravelledX);
  this.y = Math.round(origin.y + distanceTravelledY);

  // Draw!
  this.drawBoid();

  if (distanceTravelled < totalDistance) {
    // Schedule update to be called just before the next repaint
    requestAnimationFrame(update);
  }
}

// The distance you want to move
var distance = 1; // In distance units

// Speed you want to move at
var speed = 0.005 / 1000; // In distance units per millisecond

// Storage for the time when your animation started
var startTime;

// The start point, in distance units
var origin = {
  x: 0,
  y: 0
};

// The destination, in distance units
var destination = {
  x: 100,
  y: 75
};

// Distance to travel
var deltaX = (destination.x - origin.x);
var deltaY = (destination.y - origin.y);
var totalDistance = Math.sqrt( Math.pow(deltaX, 2) + Math.pow(deltaY, 2) );

// Storage for the contribution of each component per unit distance
var xPerUnitDistance,
    yPerUnitDistance;

if (totalDistance > 0) { 
  // Start animating!
  xPerUnitDistance = deltaX / totalDistance;
  yPerUnitDistance = deltaY / totalDistance;

  // Get the start time
  startTime = window.performance.now ?
              // Some browsers use high-precision timers
              (performance.now() + performance.timing.navigationStart) : 
              Date.now(); // A fallback for those that don't

  update(startTime);
}

更新: Adamは、 Chrome が高精度のタイマーを使用していることを指摘しました。コードが更新されました。

于 2013-07-11T07:03:39.560 に答える
0

これは基本的なキネマティクスであり、その答えは目的のモーションのタイプによって異なります。

一定の速度が必要な場合は、次の擬似コードのようなものが必要になります。

function moveConstantVelocity(curPos, targetPos, speed, t)
{
    /*
     * curPos - Current position of object (curPos.x, curPos.y)
     * targetPos - Destination position (targetPos.x, targetPos.y)
     * speed - Pixels-per-second to move
     * t - Seconds elapsed since previous move command
     */
    delta.x = targetPos.x - curPos.x;
    delta.y = targetPos.y - curPos.y;
    distance = sqrt(delta.x*delta.x + delta.y*delta.y);

    if (speed*t > distance)
    {
        // don't overshoot target
        newPos.x = targetPos.x;
        newPos.y = targetPos.y;
    }
    else
    {
        // Compute movement vector by normalizing delta vector
        // and then scaling it by distance traveled
        movement.x = (delta.x/distance)*speed*t;
        movement.y = (delta.y/distance)*speed*t;

        // apply movement
        newPos.x = origPos.x + movement.x;
        newPos.y = origPos.y + movement.y;
    }

    return newPos;
}
于 2013-07-11T05:57:31.877 に答える