4

我正在尝试使用 HTML5 画布制作 Pong 克隆。我想在比赛场地的中间画一条虚线,就像在原始 Pong 中找到的那样。我通过扩展CanvasRenderingContext2D对象来做到这一点,如David Geary 的优秀书中所示:

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()函数只占用了 CPU 时间的 0.46%。另外我不确定(program)应该表示什么。关于什么可能导致缓慢的任何想法?

您还可以在我的Github repo上看到我目前拥有的完整代码。

4

1 回答 1

1

每次调用时,您都会在默认路径上累积对 lineTo 的所有调用,ctx.dashedLine并且调用 stroke 将在应用程序启动后描边路径中的所有行。因为您正在运行动画,所以当每帧调用 stroke 时,路径很快就会有很多线要绘制。

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

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

演示

于 2013-06-08T17:33:13.677 回答