瓷砖无法在画布上正确显示

时间:2017-11-19 11:38:04

标签: javascript canvas tile

我正在制作一个需要平铺背景的小游戏,我从png tileSet(16x16平铺)中挑选的平铺。即使图块是16x16,它们也会在spriteSheet的画布上显示为32x32图块(请参阅下面的代码)。 问题是,当我人工放大瓷砖的尺寸时,它需要一小块瓷砖紧挨着它。图像可能比文字描述得更好:

Zoom on the background

你可以在水中看到,有一条粉红色的线,不应该在这里(我检查了瓷砖组上没有分离,0,0在我相信的正确位置)。我还尝试使用原始尺寸的瓷砖(16x16而不是32x32)作为背景,没有看到粉红色的线条,灰色网格也消失了:

所以我猜它来自32x32,但我不知道如何解决它... 这是我用来加载tileset并显示背景的代码:

loadImage('/img/dungeon.png')
.then(image => {
  const sprites = new SpriteSheet(image, 16, 16);
  sprites.define('stone_floor', 1, 0, 32, 32);
  sprites.define('water', 2, 7, 32, 32);
  sprites.define('wall_top', 2, 0, 32, 32);
  sprites.define('void', 0, 0, 32, 32);
  sprites.define('stone_floor&water', 3, 7, 32, 32);

  loadLevel('1-2')
  .then(level => {
    drawBackground(level.background, context, sprites);
  })
});

SpriteSheet类:

class SpriteSheet {
  constructor(image, width, height, offset = 0){
    this.image = image;
    this.width = width;
    this.height = height;
    this.offset = offset;
    this.tiles = new Map();
  }
  define(name, x, y, imgw, imgh){
    const buffer = document.createElement('canvas');
    buffer.width = imgw;
    buffer.height = imgh;
    buffer
        .getContext('2d')
        .drawImage(this.image,
                  x * this.width + x*this.offset, y * this.height + y*this.offset,
                  this.width, this.height,
                  0, 0, imgw, imgh);
    this.tiles.set(name, buffer);
  }
  draw(name, context, x, y){
    const buffer = this.tiles.get(name);
    context.drawImage(buffer, x, y);
  }
  drawTile(name, context, x, y){
    const buffer = this.tiles.get(name);
    context.drawImage(buffer, x * buffer.width, y * buffer.height);
  }
}

PS:这个项目高度基于MethMethMethod的教程:video

1 个答案:

答案 0 :(得分:0)

根据@ Blindman67的评论:

  

相邻图块的出血是由于向上缩放图块时的双线性过滤。简单的解决方案是转动瓷砖的双线性过滤。 ctx.imageSmoothingEnabled = false;如果您希望保持过滤,那么唯一的选择是将图块大小增加到18,在图块周围添加边框以匹配边缘颜色。您仍然只渲染16 * 16图块,但过​​滤将从边框像素而不是相邻图块进行采样。

我能够解决我的问题,虽然提出的第一个选项不起作用(关闭图像平滑)。我设法修改了我的spriteSheet类,以便它首先通过将1个18x18图块覆盖相同的图块,16x16并居中来创建一个18x18px的缓冲图像:

defineTile(name, x, y, imgw, imgh) {
    const img_buffer = document.createElement('canvas');
    img_buffer.width = this.width + 4;
    img_buffer.height = this.height + 4;
    img_buffer
      .getContext('2d')
      .drawImage(this.image,
        x * this.width + x * this.offset, y * this.height + y * this.offset,
        this.width, this.height,
        0, 0, this.width + 4, this.height + 4);
    img_buffer
      .getContext('2d')
      .drawImage(this.image,
        x * this.width + x * this.offset, y * this.height + y * this.offset,
        this.width, this.height,
        2, 2, this.width, this.height);

    const buffer = document.createElement('canvas');
    buffer.width = imgw;
    buffer.height = imgh;
    buffer
      .getContext('2d')
      .drawImage(img_buffer,
        2, 2,
        this.width, this.height,
        0, 0, imgw, imgh);
    this.tiles.set(name, buffer);
  }  

即使我不知道这是否是最优化的方式,但它能很好地完成工作!我对任何可以使这部分当然更好的建议持开放态度,但我认为问题已经解决了。