0

我正在尝试在两个计算点之间为画布周围的对象设置动画。但是,我使用的方法似乎没有考虑点之间的距离。例如,远距离的动画制作时间与短距离动画的时间相同。

以一致的速度为对象设置动画的最佳方法是什么?

/**
 * 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的是,无论如何都有 4ms 的最小延迟。真的!而是依赖代码运行时的时钟。

更好的是,现代浏览器有一个方法叫做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 回答