在画布上平稳地从A点移动到B点

Moving object from A to B smoothly across canvas

本文关键字:移动      更新时间:2023-09-26

我正在尝试使用HTML画布和常规javascript平滑地从A点移动对象到B点。

点A是坐标集合

点B为光标所在位置。

我做了一个jsfiddle: https://jsfiddle.net/as9fhmw8/

while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
    {
        ctx.save();
        ctx.beginPath();
        ctx.translate(projectile.x, projectile.y);
        ctx.arc(0,0,5,0,2*Math.PI);
        ctx.fillStyle = "blue";
        ctx.fill();
        ctx.stroke();
            ctx.restore();
        if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
        {
            var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);
            projectile.x += (stepsize + 1);
        }
        if(projectile.mouseY < projectile.y)
        {
            var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);
            projectile.y -= (stepsize + 1);
        }
    }

本质上我不能弄清楚的是让while循环变慢(这样它就会看起来像动画,而不是每次迭代都显示结果)。

我也不知道如何防止Arc复制,从而创建一条永久的线,而不是看起来从a点移动到b点。

这里的平滑动画实际上是关于确定每次循环迭代时对象移动的距离。

这里涉及到一点数学,但还不算太糟。

速度

在你的例子中,速度就是粒子在一段时间内沿任何给定方向运动的速度。如果你想让你的粒子在4秒内移动200px,那么速度将是50px / second

有了这些信息,你可以很容易地确定给定一段任意长度的时间,一个粒子需要移动(动画)多少像素。

pixels = pixelsPerSecond * seconds

知道要移动多少像素很好,但不能转换为单独的X和Y坐标。这就是向量的作用

向量

数学中的向量是方向和大小的度量。就我们的目的而言,这就像将速度与角度(47°)结合起来。

向量的一个重要性质是它可以被分解成单独的X和Y分量(对于二维空间)

所以如果我们想要移动50px / second处的粒子以47°的角度,我们可以这样计算一个向量:

function Vector(magnitude, angle){
   var angleRadians = (angle * Math.PI) / 180;
   this.magnitudeX = magnitude * Math.cos(angleRadians);
   this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);

奇妙之处在于,这些值可以简单地添加到任何一组X和Y坐标中,以根据速度计算移动它们。

鼠标移动矢量

以这种方式建模你的对象有一个额外的好处,那就是使事情变得漂亮并且在数学上是一致的。粒子和鼠标之间的距离只是另一个矢量。

我们可以用更多的数学方法来计算距离和角度。还记得毕达哥拉斯吗?原来他很聪明。

function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
   var x = x2 - x1,
       y = y2 - y1;
   return {
      // x^2 + y^2 = r^2
      distance: Math.sqrt(x * x + y * y),
      // convert from radians to degrees
      angle: Math.atan2(y, x) * 180 / Math.PI
   }
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);

顺利动画

以一种不笨拙的方式在屏幕上动画你的东西意味着做以下事情:

  1. 尽可能快地运行你的动画循环
  2. 确定距离上次
  3. 已经过了多少时间
  4. 根据经过的时间移动每个项目。
  5. 重新绘制屏幕

对于动画循环,我将使用requestAnimationFrame API而不是setInterval,因为它将具有更好的整体性能。

清空屏幕

当你重新绘制屏幕时,只要在整个屏幕上画一个大矩形,用任何你想要的背景颜色,然后再重新绘制你的项目。

ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);

把它放在一起

这里是一个小提琴演示所有这些技术:https://jsfiddle.net/jwcarroll/2r69j1ok/3/