画布渐变性能

4

我当前正在使用canvas编写一个小游戏。针对该游戏,我需要一种雾化效果来隐藏地图的大部分部分,并且只有玩家周围的一个小区域应该是可见的。因此,我使用第二个canvas来覆盖游戏发生的那个画布,用渐变(从透明到黑色)填充它:

function drawFog(){
fogc.clearRect(0,0,700,600);
// Create gradient
var grd=fogc.createRadialGradient(player.getPosX(),player.getPosY(),0,player.getPosX(),player.getPosY(),100);
grd.addColorStop(0,"rgba(50,50,50,0)");
grd.addColorStop(1,"black");

// Fill with gradient
fogc.fillStyle=grd;
fogc.fillRect(0,0,700,600);
}

不幸的是,这会导致巨大的性能问题,因为它将在每一帧重新绘制。

我想问一下是否有更好的解决方案来实现相同的效果,以获得更好的性能。


只填充200x200区域渐变会有帮助吗?您可以用黑色填充整个画布(或仅在黑色中重新填充先前的渐变部分),擦除渐变部分,然后绘制渐变。 - Passerby
实际上我刚试了一下,没有任何效果,我认为问题在于梯度本身。 - Danmoreng
使用一个额外的不可见的200x200画布来“缓存”渐变效果如何?然后你只需要使用drawImage即可,我认为这样会更快。 - Passerby
那个有点有效。性能不如没有雾气时好(Firefox使用雾气时CPU占用率为20%,而没有雾气时只有5%),但现在动画很流畅。谢谢! - Danmoreng
1个回答

6

将渐变缓存到离屏画布中,然后使用drawImage()在画布中绘制:

  • 创建与雾大小相同的离屏画布
  • 绘制渐变
  • 需要时使用离屏画布作为图像来呈现雾。

这样可以消除创建和计算渐变的处理。绘制图像基本上是一种复制操作(还有一点点更多,但性能非常好)。

function createFog(player) {

    // Create off-screen canvas and gradient
    var fogCanvas = document.createElement('canvas'),
        ctx = fogCanvas.getContext('2d'),
        grd = fogc.createRadialGradient(player.getPosX(),
                                        player.getPosY(),
                                        0,player.getPosX(),
                                        player.getPosY(),100);

    fogCanvas.width = 700;
    fogCanvas.height = 700;

    grd.addColorStop(0,"rgba(50,50,50,0)");
    grd.addColorStop(1,"black");

    // Fill with gradient
    ctx.fillStyle = grd;
    ctx.fillRect(0,0,700,600);

    return fogCanvas;
}

现在,您可以直接在从上述函数返回的画布中绘制,而无需每次都创建渐变:
var fog = createFog(player);
ctx.drawImage(fog, x, y);

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