慢速性能绘制HTML5 Canvas中的虚线

时间:2013-06-08 15:38:36

标签: javascript performance html5-canvas

我正在尝试使用HTML5画布制作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秒,它就会开始急剧减速到无法播放的程度,浏览器的CPU使用率在Firefox和Chrome上都会徘徊134%左右。只有当我渲染虚线时才会出现缓慢的情况。我不确定会发生什么,但下面我还通过Chrome Inspectors探查器运行了我的代码并获取以下内容:

enter image description here

我的renderBackground()功能仅占用了0.46%的CPU时间。此外,我不确定(program)应该表示什么。关于什么可能导致缓慢的任何想法?

此外,您可以在我的Github repo上查看到目前为止的完整代码。

1 个答案:

答案 0 :(得分:2)

每次调用ctx.dashedLine时,您都会在默认路径上累积lineTo的所有调用,并且自应用程序启动以来,调用笔划将描述路径中的所有行。因为您正在运行动画,所以在每帧调用笔划时,路径将快速绘制很多行。

ctx.beginPath()之前添加ctx.dashedLine以解决问题。

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();
}

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

Demo