当我尝试在 HTML5 Canvas 中移动 PNG 图像时,图像不稳定
PNG image choppy when I try to move it in HTML5 Canvas
所以我来的时候正在用HTML5Canvas和纯Javascript做游戏
遇到一个恼人的问题。当我尝试使用 setInterval 移动我的图片时,它可以工作,但图片会像波涛汹涌一样抽动。我的猜测是,这与图像需要每 10 毫秒加载一次有关。请帮我解决这个问题。
示例代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset = "UTF-8" />
</head>
<body>
<canvas id = "myCanvas" width = "1000" height = "500" style="border:1px solid #000000;">
</canvas>
<script type = "text/javascript">
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = 0;
var image = new Image();
image.src = 'spaceship.png';
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
image.src = 'spaceship.png';
image.onload = function(){
ctx.drawImage(image, x, 0);
}
x += 2;
}
setInterval(draw,10);
</script>
</body>
</html>
首先,10ms的间隔太短了。即使是 60fps,你也会有 ~16.67ms 的间隔。
此外,如果可用,您在制作动画时不应使用 setInterval
,而应使用 requestAnimationFrame
。这应该会导致支持它的浏览器上的动画更加流畅。
最后应该优化的是你每帧将图像移动 2px。您不能确定每个帧都在相同的时间间隔后被调用。像这样,您将在快速计算机上获得更快的动画,而在慢速计算机上获得慢速动画。您应该使用当前时间和自上次动画帧以来经过的时间增量(例如 Date.now()
)
最后要注意的是图像的 onload
回调只能调用一次。那是在执行任何动画或绘图之前。所以只有在加载图像后,动画才会开始。
移动球的例子:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
lastTimestamp,
imageX = 0;
canvas.width = 300;
canvas.height = 300;
var image = new Image();
image.onload = function () {
requestAnimationFrame(draw);
};
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAolBMVEUAAAARqu4YrO4bre4aq+wbrOocrOocq+sbreobquocrOkcrOobq+oaqugdresir+sosewus+w0te01tu06t+0+ue4/ue5GvO5Ov+9cxPBfxfFoyPFwy/J0zPJ4zvN6z/OA0fSE0vSG0/SJ1PSQ1vWR1/WT1/WV2PWY2faZ2vad2/ai3fej3fel3ven3/ev4vix4/i45vm65vm85/m+6PnA6fpEpw5TAAAADnRSTlMADx8vX29/j5+vv8/f79ErPTAAAADdSURBVBgZBcELThsxFADAef5sQkAVEr3/JcsSNrafOxNAKT2wRyYIiFsPwB7XRqC+FY9Smpnjks9FEO/l7c8BOP+NPLfKe/34qgDHx5VtqI7j9hcQrdV9/917lbj5BGhHa618ukVp8TgAGpr7I1rpDgAbyaGXagMYyxpstYUyOmAtuIpouFavAOYr0XZkmbO2FthzJGm31ebBWhcA0yrDAgBYRlmuBADmr1XytU8AkKdXVqvvbAFgnplPldVz9gDM79zPVNmjuUTBvH6sMwmIewdwvTYCqL0H9msk+A8oZ3I4nbdKXwAAAABJRU5ErkJggg==";
function draw() {
var now = Date.now(),
timeDelta = (now - (lastTimestamp || now)) / 1000; // in seconds
imageX += timeDelta * 30; // meaning: 30px per second
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(image, imageX, 0);
lastTimestamp = now;
requestAnimationFrame(draw);
}
<canvas id="canvas" />
所以我来的时候正在用HTML5Canvas和纯Javascript做游戏 遇到一个恼人的问题。当我尝试使用 setInterval 移动我的图片时,它可以工作,但图片会像波涛汹涌一样抽动。我的猜测是,这与图像需要每 10 毫秒加载一次有关。请帮我解决这个问题。
示例代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset = "UTF-8" />
</head>
<body>
<canvas id = "myCanvas" width = "1000" height = "500" style="border:1px solid #000000;">
</canvas>
<script type = "text/javascript">
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = 0;
var image = new Image();
image.src = 'spaceship.png';
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
image.src = 'spaceship.png';
image.onload = function(){
ctx.drawImage(image, x, 0);
}
x += 2;
}
setInterval(draw,10);
</script>
</body>
</html>
首先,10ms的间隔太短了。即使是 60fps,你也会有 ~16.67ms 的间隔。
此外,如果可用,您在制作动画时不应使用 setInterval
,而应使用 requestAnimationFrame
。这应该会导致支持它的浏览器上的动画更加流畅。
最后应该优化的是你每帧将图像移动 2px。您不能确定每个帧都在相同的时间间隔后被调用。像这样,您将在快速计算机上获得更快的动画,而在慢速计算机上获得慢速动画。您应该使用当前时间和自上次动画帧以来经过的时间增量(例如 Date.now()
)
最后要注意的是图像的 onload
回调只能调用一次。那是在执行任何动画或绘图之前。所以只有在加载图像后,动画才会开始。
移动球的例子:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
lastTimestamp,
imageX = 0;
canvas.width = 300;
canvas.height = 300;
var image = new Image();
image.onload = function () {
requestAnimationFrame(draw);
};
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAolBMVEUAAAARqu4YrO4bre4aq+wbrOocrOocq+sbreobquocrOkcrOobq+oaqugdresir+sosewus+w0te01tu06t+0+ue4/ue5GvO5Ov+9cxPBfxfFoyPFwy/J0zPJ4zvN6z/OA0fSE0vSG0/SJ1PSQ1vWR1/WT1/WV2PWY2faZ2vad2/ai3fej3fel3ven3/ev4vix4/i45vm65vm85/m+6PnA6fpEpw5TAAAADnRSTlMADx8vX29/j5+vv8/f79ErPTAAAADdSURBVBgZBcELThsxFADAef5sQkAVEr3/JcsSNrafOxNAKT2wRyYIiFsPwB7XRqC+FY9Smpnjks9FEO/l7c8BOP+NPLfKe/34qgDHx5VtqI7j9hcQrdV9/917lbj5BGhHa618ukVp8TgAGpr7I1rpDgAbyaGXagMYyxpstYUyOmAtuIpouFavAOYr0XZkmbO2FthzJGm31ebBWhcA0yrDAgBYRlmuBADmr1XytU8AkKdXVqvvbAFgnplPldVz9gDM79zPVNmjuUTBvH6sMwmIewdwvTYCqL0H9msk+A8oZ3I4nbdKXwAAAABJRU5ErkJggg==";
function draw() {
var now = Date.now(),
timeDelta = (now - (lastTimestamp || now)) / 1000; // in seconds
imageX += timeDelta * 30; // meaning: 30px per second
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(image, imageX, 0);
lastTimestamp = now;
requestAnimationFrame(draw);
}
<canvas id="canvas" />