Canvas 个动画 运行 同时使用 rAF 和 setInterval
Canvas animations running at the same time using both rAF and setInterval
我有一个包含不同组件的动画。
- 一个人走路
- 充满腔室的气体
这些组件中的每一个在单独使用时都运行良好,但是当我尝试将两者结合使用时,动画根本无法运行。
动画的当前状态,气体正常工作。然而,这个人在视线中忽隐忽现,有时他无处可见。
这里的问题是您每 200 毫秒绘制一次人,但是 canvas 的其余部分是在浏览器准备好后立即绘制的,由于 requestAnimationFrame(paint);
,这将清除那个人。
解决方法如下:
- 将你的助行器的所有绘画内容移动到 paint() 函数中
- 将所有变量的声明从 animationFrames
到 dy
移动到 walker() 函数之外,您希望它们是全局的而不是函数内的局部变量(因为您将绘制画中人 ()-函数)
而不是同时使用requestAnimationFrame
和setInterval
...
requestAnimationFrame
(rAF) 会产生更好的性能,因为它会尝试将绘图与浏览器刷新周期同步。
因此,如果将所有动画都放在 requestAnimationFrame
中,性能会更好。
您可以使用单个 rAF 来驱动所有动画,方法是为每个动画创建一个对象(一个人对象和一个气体对象)。
每个对象包含:
当前动画状态(足够的信息来绘制对象)。
此动画的频率和更新下一帧动画所需的数据
这是一个示例,它每 167 毫秒为一个矩形制作动画,每
制作一个圆
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var actions=[];
//
actions.push({
nextTime:0,
delay:1000/60*10,
fn:rect,
dx:1,
dy:1,
x:20,
y:20,
options:{w:20,h:15,angle:0,fill:'skyblue'}
});
//
actions.push({
nextTime:0,
delay:1000/60*3,
fn:circle,
dx:-1,
dy:1,
x:200,
y:25,
options:{r:12,fill:'lightsalmon'}
});
requestAnimationFrame(animate);
var c=0;
function animate(time){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<actions.length;i++){
var a=actions[i];
a.fn(a);
if(time>a.nextTime){
a.nextTime=time+a.delay;
a.x+=a.dx;
a.y+=a.dy;
}
}
requestAnimationFrame(animate);
}
function rect(r){
ctx.fillStyle=r.options.fill;
ctx.fillRect(r.x,r.y,r.options.w,r.options.h);
}
function circle(c){
ctx.beginPath();
ctx.arc(c.x,c.y,c.options.r,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=c.options.fill;
ctx.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
我有一个包含不同组件的动画。
- 一个人走路
- 充满腔室的气体
这些组件中的每一个在单独使用时都运行良好,但是当我尝试将两者结合使用时,动画根本无法运行。
动画的当前状态,气体正常工作。然而,这个人在视线中忽隐忽现,有时他无处可见。
这里的问题是您每 200 毫秒绘制一次人,但是 canvas 的其余部分是在浏览器准备好后立即绘制的,由于 requestAnimationFrame(paint);
,这将清除那个人。
解决方法如下:
- 将你的助行器的所有绘画内容移动到 paint() 函数中
- 将所有变量的声明从 animationFrames
到 dy
移动到 walker() 函数之外,您希望它们是全局的而不是函数内的局部变量(因为您将绘制画中人 ()-函数)
而不是同时使用requestAnimationFrame
和setInterval
...
requestAnimationFrame
(rAF) 会产生更好的性能,因为它会尝试将绘图与浏览器刷新周期同步。
因此,如果将所有动画都放在 requestAnimationFrame
中,性能会更好。
您可以使用单个 rAF 来驱动所有动画,方法是为每个动画创建一个对象(一个人对象和一个气体对象)。
每个对象包含:
当前动画状态(足够的信息来绘制对象)。
此动画的频率和更新下一帧动画所需的数据
这是一个示例,它每 167 毫秒为一个矩形制作动画,每
制作一个圆var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var actions=[];
//
actions.push({
nextTime:0,
delay:1000/60*10,
fn:rect,
dx:1,
dy:1,
x:20,
y:20,
options:{w:20,h:15,angle:0,fill:'skyblue'}
});
//
actions.push({
nextTime:0,
delay:1000/60*3,
fn:circle,
dx:-1,
dy:1,
x:200,
y:25,
options:{r:12,fill:'lightsalmon'}
});
requestAnimationFrame(animate);
var c=0;
function animate(time){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<actions.length;i++){
var a=actions[i];
a.fn(a);
if(time>a.nextTime){
a.nextTime=time+a.delay;
a.x+=a.dx;
a.y+=a.dy;
}
}
requestAnimationFrame(animate);
}
function rect(r){
ctx.fillStyle=r.options.fill;
ctx.fillRect(r.x,r.y,r.options.w,r.options.h);
}
function circle(c){
ctx.beginPath();
ctx.arc(c.x,c.y,c.options.r,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=c.options.fill;
ctx.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>