我正在尝试使用HTML画布和常规javascript将对象从A点平滑移动到B点。
A点是一组坐标
B点是光标所在的位置。
我制作了迄今为止我所掌握的内容: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点。
答案 0 :(得分:7)
这里的平滑动画实际上是关于确定循环的每次迭代移动对象的距离。
这里涉及一些数学,但它并不太糟糕。
您的情况下的速度只是粒子在一段时间内沿任何给定方向行进的速度。如果您希望粒子在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);
以不生涩的方式在屏幕上动画您的内容意味着执行以下操作:
对于动画循环,我会使用requestAnimationFrame
API代替setInterval
,因为它会有更好的整体效果。
清除屏幕
此外,当您重新绘制屏幕时,只需在重新绘制项目之前以任何背景颜色在整个事物上绘制一个大矩形。
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
这是一个演示所有这些技巧的小提琴:https://jsfiddle.net/jwcarroll/2r69j1ok/3/