在HTML5 Canvas中绘制虚线的性能较慢

4
我正在尝试使用HTML5画布制作一个Pong克隆版。我想在游戏场地中央绘制一个虚线,就像原版的Pong一样。我通过扩展CanvasRenderingContext2D对象来实现这一点,如David Geary's的优秀著作所示:
CanvasRenderingContext2D.prototype.dashedLine = function (x1, y1, x2, y2, dashLength) {
    dashLength = dashLength === undefined ? 5 : dashLength;

    var deltaX = x2 - x1;
    var deltaY = y2 - y1;
    var numDashes = Math.floor(
              Math.sqrt(deltaX * deltaX + deltaY * deltaY) / dashLength);

    for (var i=0; i < numDashes; ++i) {
        context[ i % 2 === 0 ? 'moveTo' : 'lineTo' ]
         (x1 + (deltaX / numDashes) * i, y1 + (deltaY / numDashes) * i);
    }

我接着有一个render()函数,它实际上是在画布上渲染元素的所有调用。其中包括我的renderBackground()函数,它着色背景并绘制虚线:

function render() {
    ctx.clearRect(0, 0, cWidth, cHeight);
    renderBackground();
    // Rest removed for brevity
}

function renderBackground() {
    ctx.lineWidth = 5;
    ctx.strokeStyle = '#FFFFFF';
    ctx.fillStyle = '#000000';
    ctx.fillRect(0, 0, cWidth, cHeight);
    ctx.dashedLine(0, 0, 0, cHeight, 10);
    ctx.stroke()
}

最后我有一个名为animLoop()的函数,它实际上调用render()函数,并利用requestAnimationFrame()来实现更平滑的动画效果:

function animLoop() {
    render();
    requestAnimationFrame(animLoop);
}

window.requestAnimationFrame = (function() {
    return (
           window.requestAnimationFrame       ||
           window.webkitRequestAnimationFrame ||
           window.mozRequestAnimationFrame    ||
           function( callback ){
               window.setTimeout(callback, 1000 / 60);
           }
        );
})();

如果我让我的游戏运行超过30秒,它会显著减慢,达到无法玩的程度,并且Firefox和Chrome浏览器的CPU使用率都在134%左右。只有在渲染虚线时才会出现缓慢。我不确定发生了什么,但是我还通过Chrome检查器的分析器运行了我的代码,结果如下:

enter image description here

我的renderBackground()函数只占用了0.46%的CPU时间。而且我不确定(program)应该表示什么。你有想法是什么导致了速度变慢吗?

另外,您可以在我的Github存储库上看到我目前的完整代码。


3
看起来你正在将所有的lineTo调用累积到默认路径上。在ctx.dashedLine之前尝试放置ctx.beginPath() - Gustavo Carvalho
1个回答

1
每次调用ctx.dashedLine时,您都会在默认路径上累积所有lineTo的调用,并且调用stroke将自应用启动以来路径中的所有线条进行描边。因为您正在运行动画,所以当每帧调用stroke时,路径将有很多线要绘制。
ctx.dashedLine之前添加ctx.beginPath()可以解决这个问题。
function renderBackground() {
    ctx.lineWidth = 5;
    ctx.strokeStyle = '#FFFFFF';
    ctx.fillStyle = '#000000';
    ctx.fillRect(0, 0, cWidth, cHeight);
    ctx.beginPath(); // <-- add it here 
    ctx.dashedLine(0, 0, 0, cHeight, 10);
    ctx.stroke();
}

使用路径绘图时,您使用的是虚拟的“笔”或“指针”。因此,您将使用begin path创建虚拟路径,绘制线条,最后描边这些线条。在下一帧中,您将开始一个新的虚拟路径,在路径中绘制新的线条并再次描边。这样可以保持性能稳定。

演示


没错,就是这样。忘了 beginPath()。谢谢! - user670595

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接