javascript – 慢速性能绘制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探查器运行了我的代码并获取以下内容:

我的renderBackground()函数只占用了0.46%的CPU时间.此外,我不确定(程序)应该表示什么.关于什么可能导致缓慢的任何想法?

你也可以在我的Github repo上看到我到目前为止的完整代码.

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

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

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

Demo

点赞