5

我正在将游戏地图绘制到画布中。地面由瓷砖组成 - 简单的 64x64 png 图像。

当我在 Chrome 中绘制它时,它看起来不错(左),但是当我在 Firefox/Opera/IE 中绘制它(右)时,我得到了可见的边缘: 在此处输入图像描述

当我使用四舍五入的数字时,问题就消失了:

ctx.drawImage(img, parseInt(x), parseInt(y), w, h);

但这在我使用缩放时无济于事:

ctx.scale(scale); // anything from 0.1 to 2.0

我也尝试了这些,但没有改变:

  1. ctx.drawImage(img, 5, 5, 50, 50, x, y, w, h); // so not an issue of clamping
  2. ctx.imageSmoothingEnabled = false;
  3. image-rendering: -moz-crisp-edges; (css)

有没有办法让它在 ff/op/ie 中工作?


编辑:找到部分解决方案

在宽度/高度上添加 1 个像素并按比例(宽度+1/比例)进行补偿似乎有帮助:

ctx.drawImage(props.img, 0, 0, width + 1/scale, height + 1/scale);

它制造了一些人工制品,但我认为这是可以接受的。在此图像上,您可以看到没有边缘的绿色瓷砖,以及未补偿的蓝色窗口,仍然有可见的边缘:

固定的

4

4 回答 4

3

最简单的解决方案(我认为最有效)是在绘制游戏的背景图块时使用重叠 1 个像素的图块(大 1x1 或 2x2)。

没什么特别的,只是画得比平时多一点。这避免了将额外转换引入组合的复杂性和性能考虑。

例如:

var img = new Image();
img.onload = function () {
    for (var x = 0.3; x < 200; x += 15) {
        for (var y = 0.3; y < 200; y += 15) {
            ctx.drawImage(img, 0, 0, 15, 15, x, y, 15, 15);
            // If we merely use 16x16 tiles instead,
            // this will never happen:
            //ctx.drawImage(img, 0, 0, 16, 16, x, y, 16, 16);
        }
    }
}
img.src = "http://upload.wikimedia.org/wikipedia/en/thumb/0/06/Neptune.jpg/100px-Neptune.jpg";

之前:http: //jsfiddle.net/d9MSV

之后:http: //jsfiddle.net/d9MSV/1/


请注意,正如提问者指出的那样,额外的像素需要考虑缩放,因此更正确的解决方案是他的修改:http: //jsfiddle.net/d9MSV/3/

于 2013-07-18T20:47:33.323 回答
1

原因

这是由抗锯齿引起的。

Canvas 仍在进行中,浏览器有不同的实现来处理抗锯齿。

可能的解决方案

1

您可以尝试在 Firefox 中关闭图像的抗锯齿,如下所示:

context.mozImageSmoothingEnabled = false;

在 Chrome 中:

context.webkitImageSmoothingEnabled = false;

并像这样向元素添加一个类(应该与 Opera 一起使用):

canvas {
    image-rendering: optimizeSpeed;             // Older versions of FF
    image-rendering: -moz-crisp-edges;          // FF 6.0+
    image-rendering: -webkit-optimize-contrast; // Webkit
    image-rendering: -o-crisp-edges;            // OS X & Windows Opera (12.02+)
    image-rendering: optimize-contrast;         // Possible future browsers.
    -ms-interpolation-mode: nearest-neighbor;   // IE
}

这是我为查看关闭抗锯齿效果所做的浏览器测试:

ANTI-ALIAS BROWSER TEST

2

将整个画布平移 0.5 磅。

ctx.translate(0.5, 0.5);

这并不总是有效,并且可能与其他翻译发生冲突。但是,您可以每次添加一个固定的偏移量:

ctx.translate(scrollX + 0.5, scrollY + 0.5);

3

另一种选择是做一个妥协,你要么用一个额外的像素填充瓷砖,我不建议这样做,因为你会得到额外的工作来维护它。

4

此方法将图块按比例绘制,以便它们重叠:

ctx.drawImage(tile, x, y, 65, 65); //source tile = 64x64

这可能足以弥补故障。结合关闭抗锯齿(或使用最近邻),它不会影响大部分平铺图形,但由于缩放,它可能会稍微降低性能。

如果您关闭抗锯齿(并且它本身不起作用),开销将是最小的,因为有些会插入图像。

5

只需绘制所有偏移 -1 位置(即网格 = 63x63)。当然,这会搞砸有关检查的所有其他事情,所以...

于 2013-07-18T14:48:02.600 回答
0

在涉及除法时,在每个瓷砖绘制中使用 Math.floor,如下所示:

    ctx.drawImage(image,Math.floor(xpos/3),ypos+1)

此外,如果您要绘制一个循环,它会调用自身,请始终使用 requestAnimationFrame。我不知道为什么,但是自从我从计时器超时转移到 requestAnimationFrame 之后,我就没有更多的工件了。

于 2015-01-27T00:44:18.567 回答
0

我将所有图块绘制到一个大小完美的缓冲区,然后使用 drawImage 将该缓冲区绘制到显示画布,它负责缩放。如果您有 16x16 的图块,请将缓冲区设为 16 的倍数,例如 256x128 或 64x96 或类似的东西。这消除了由于使用缩放尺寸绘图而产生的瓷砖之间的空间。唯一的缺点是您必须绘制两次完整的背景:一次在像素完美空间中绘制背景,一次将缩放后的图像绘制到最终的显示画布上。请记住保持缓冲区和显示画布之间的纵横比以避免倾斜最终图像。

于 2018-01-19T01:41:15.253 回答