如何平滑我的JavaScript动画?

如何平滑我的JavaScript动画?,javascript,canvas,Javascript,Canvas,我从以下地址的代码开始: 我将其更新为使用requestAnimFrame,如下所示: window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callba

我从以下地址的代码开始:

我将其更新为使用requestAnimFrame,如下所示:

window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        function( callback ){
            window.setTimeout(callback, 1000 / 60);
        };
})();
演示可在以下位置获得:


在我看来,在Chrome浏览器下运行的动画在更高的速度下仍然有点模糊。我能做什么进一步的优化呢?

我不知道你说的模糊是什么意思,但20像素的步骤会使动画变得非常粗糙(降低它们以使球不那么模糊/“跳跃”)

在任何情况下,如果要优化此代码,可以调整以下内容:

//put this outside the loop, no need to get it everytime
context= myCanvas.getContext('2d');

//record previous position and size and only clear that area
//instead of the complete canvas for each time
context.clearRect(0,0,300,300);

//pre-render this object to an off-screen canvas and use
//drawImage(osCanvas, x, y) instead
context.beginPath();
context.fillStyle="#0000ff";
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
当然,如果可用,请使用
requestAnimationFrame
,使动画与监视器vblank保持同步(消除抖动)

但是把它放在你的主循环里

以下是这些优化的结果:

没有这么多DOM元素和iframe:

您无法对DOM更新执行任何操作,因此为了减少事件队列中重新绘制和其他事件的影响,建议在同一窗口中使用尽可能少的其他元素。如果可能,对元素使用固定或绝对位置,避免阴影和圆角边框

优化进近的源输出:

function draw() {
    //here we only clear last draw and draw the cached ball
    context.clearRect(oldX - 2, oldY -2 ,dia +4,dia +4);
    context.drawImage(canvas,x, y);

    oldX = x; //store the current x/y as old x/y for next loop
    oldY = y;

    if( x<0 || x>300) dx=-dx;
    if( y<0 || y>300) dy=-dy;

    x+=dx;
    y+=dy;
    requestAnimationFrame(draw);
}

//function to create cached ball
function createBall() {
    canvas = document.createElement('canvas');
    canvas.width = dia;
    canvas.height = dia;
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.fillStyle="#0000ff";
    ctx.arc(rad,rad,rad,0,Math.PI*2,true);
    ctx.fill();
}

createBall(); //create ball
draw();       //start anim
函数绘图(){
//在这里,我们只清除最后一个平局,并绘制缓存的球
clearRect(oldX-2,oldY-2,dia+4,dia+4);
背景.绘图图像(画布,x,y);
oldX=x;//将当前x/y存储为旧x/y,以便下一个循环
oldY=y;
如果(x300)dx=-dx;
如果(y300)dy=-dy;
x+=dx;
y+=dy;
请求动画帧(绘制);
}
//函数创建缓存球
函数createBall(){
canvas=document.createElement('canvas');
画布宽度=直径;
画布高度=直径;
var ctx=canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle=“#0000ff”;
弧(rad,rad,rad,0,数学π*2,真);
ctx.fill();
}
createBall()//创造球
draw()//开始动画

我不知道你所说的模糊是什么意思,但20像素的步长会使动画非常粗糙(降低它们以使球不那么模糊/“跳跃”)

在任何情况下,如果要优化此代码,可以调整以下内容:

//put this outside the loop, no need to get it everytime
context= myCanvas.getContext('2d');

//record previous position and size and only clear that area
//instead of the complete canvas for each time
context.clearRect(0,0,300,300);

//pre-render this object to an off-screen canvas and use
//drawImage(osCanvas, x, y) instead
context.beginPath();
context.fillStyle="#0000ff";
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
当然,如果可用,请使用
requestAnimationFrame
,使动画与监视器vblank保持同步(消除抖动)

但是把它放在你的主循环里

以下是这些优化的结果:

没有这么多DOM元素和iframe:

您无法对DOM更新执行任何操作,因此为了减少事件队列中重新绘制和其他事件的影响,建议在同一窗口中使用尽可能少的其他元素。如果可能,对元素使用固定或绝对位置,避免阴影和圆角边框

优化进近的源输出:

function draw() {
    //here we only clear last draw and draw the cached ball
    context.clearRect(oldX - 2, oldY -2 ,dia +4,dia +4);
    context.drawImage(canvas,x, y);

    oldX = x; //store the current x/y as old x/y for next loop
    oldY = y;

    if( x<0 || x>300) dx=-dx;
    if( y<0 || y>300) dy=-dy;

    x+=dx;
    y+=dy;
    requestAnimationFrame(draw);
}

//function to create cached ball
function createBall() {
    canvas = document.createElement('canvas');
    canvas.width = dia;
    canvas.height = dia;
    var ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.fillStyle="#0000ff";
    ctx.arc(rad,rad,rad,0,Math.PI*2,true);
    ctx.fill();
}

createBall(); //create ball
draw();       //start anim
函数绘图(){
//在这里,我们只清除最后一个平局,并绘制缓存的球
clearRect(oldX-2,oldY-2,dia+4,dia+4);
背景.绘图图像(画布,x,y);
oldX=x;//将当前x/y存储为旧x/y,以便下一个循环
oldY=y;
如果(x300)dx=-dx;
如果(y300)dy=-dy;
x+=dx;
y+=dy;
请求动画帧(绘制);
}
//函数创建缓存球
函数createBall(){
canvas=document.createElement('canvas');
画布宽度=直径;
画布高度=直径;
var ctx=canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle=“#0000ff”;
弧(rad,rad,rad,0,数学π*2,真);
ctx.fill();
}
createBall()//创造球
draw()//开始动画

很好的动画,你非常接近:)

没什么。首先,在设置动画时,通常希望有小的步骤,以使正在设置动画的项目不会出现起伏。第二,确保在小步设置动画时,以高频率进行(覆盖了该部分)。第三,当设置对象动画和碰撞检测是一个问题时,请确保按对象的尺寸偏移边界

我的演示改变了第一个和第三个音符

var dx=4;
var dy=4;

if(x<20 | | x>280)
dx=-dx;
如果(y<20 | | y>280)
对于示例,我还使边界框更加清晰。

很好的动画,你非常接近:)

没什么。首先,在设置动画时,通常希望有小的步骤,以使正在设置动画的项目不会出现起伏。第二,确保在小步设置动画时,以高频率进行(覆盖了该部分)。第三,当设置对象动画和碰撞检测是一个问题时,请确保按对象的尺寸偏移边界

我的演示改变了第一个和第三个音符

var dx=4;
var dy=4;

if(x<20 | | x>280)
dx=-dx;
如果(y<20 | | y>280)

我还对示例中的边界框进行了更清晰的说明。

在Chrome和Firefox中,它看起来很好。你能解释一下你所说的“模糊”是什么意思吗?你可以降低速度@Dai He意思是你看到它像3个球一样连续移动(眼睛错觉),更具体地说,我指的是重影效果@yotam所以它总是以更高的速度出现?对我来说,它在Chrome上看起来也非常平滑。在将dx和dy变量降低到2之后,这消除了任何形式的视觉错觉,我无法感知单独的帧。在Chrome和Firefox中,我觉得这很好。你能解释一下你所说的“模糊”是什么意思吗?你可以降低速度@Dai He意思是你看到它像3个球一样连续移动(眼睛错觉),更具体地说,我指的是重影效果@yotam所以它总是以更高的速度出现?对我来说,它在Chrome上看起来也非常平滑。在将dx和dy变量降低到2之后,这消除了任何形式的视觉错觉,我无法感知单个帧。