【问题标题】:JavaScript's drawContext is not mathematically correctJavaScript 绘制上下文在数学上不正确
【发布时间】:2022-01-02 01:53:03
【问题描述】:

我有一个使用 32x32 瓦片的瓦片集:

我将它绘制在画布上以显示 32x32 平铺地图。但是,数学似乎不对。为什么画布绘制的图块显然不在图块的 32x32 范围内?

例如:

如您所见,画布的 32x32 网格的左上角应该是 ONE tile...但是它被切断了:

const appDiv = document.getElementById('app');

const tileSize = 32;
const canvasSize = 480; // 32 (tiles) * 15 (columns) = 480 pixels
const tilesAcross = canvasSize / tileSize; // (Size of Canvas [480] / Tile size [32]) = 15 columns

appDiv.innerHTML = `<h2>Canvas</h2><canvas id="map" width="${canvasSize}" height="${canvasSize}">`;

function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

resizeCanvas();

// Regenerate map on resize
window.onresize = resizeCanvas;

function resizeCanvas() {
  const ctx = document.getElementById('map').getContext('2d');
  const image = new Image();
  image.src = 'https://i.postimg.cc/k4KBLBJh/terrain.png'; // Tileset

  image.onload = () => {
    for (let column = 0; column < tilesAcross; column++) {
      for (let row = 0; row < tilesAcross; row++) {
        ctx.drawImage(
          image, // Image elemnt
          randomIntFromInterval(0, 5) * 32, // sx - The x-axis of top left corner of the rect of the image to draw into context.
          randomIntFromInterval(0, 5) * 32, // sy - The y-axis of top left corner of the rect of the image to draw into context.
          32, // sWidth - The width of the rect of the image to draw into context.
          32, //  sHeight - The height of the rect of the image to draw into the destination context.
          row * 32, // dx - The x-axis coordinate in the canvas at which to place the top-left corner of the image.
          column * 32, // dy - The y-axis coordinate in the canvas at which to place the top-left corner of the image.
          32, // dWidth - The width to draw the image in the canvas. This allows scaling of the drawn image.
          32 // dHeight- The width to draw the image in the canvas. This allows scaling of the drawn image.
        );
      }
    }
  };
}
canvas {
  background: black;
}
<div id="app"></div>

<style src="./style.css"></style>

【问题讨论】:

  • 您验证了randomIntFromInterval(0, 5) * 32 实际上产生了真值?作为代码的一部分,复制您的 ctx.drawImage 讲师,将其重命名为 console.log,从该代码中删除 image 参数,然后运行。这些值有意义吗?
  • 是的,我已验证。即使只有整数 - 也是一样的。

标签: javascript html canvas


【解决方案1】:

图片中的图块不是32x32px,更像28.56px

我认为您需要重新渲染 spritesheet。您不会对此感到满意,因为您总是在边缘处有线条,其中一行/列的两个图块的像素已被插值。

如果你拉伸它们,它们就会变得模糊。

const appDiv = document.getElementById('app');

const tileSize = 32;
const canvasSize = 480; // 32 (tiles) * 15 (columns) = 480 pixels
const tilesAcross = canvasSize / tileSize; // (Size of Canvas [480] / Tile size [32]) = 15 columns

appDiv.innerHTML = `<h2>Canvas</h2><canvas id="map" width="${canvasSize}" height="${canvasSize}">`;

function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

resizeCanvas();

// Regenerate map on resize
window.onresize = resizeCanvas;

function resizeCanvas() {
  const ctx = document.getElementById('map').getContext('2d');
  const image = new Image();
  image.src = 'https://i.postimg.cc/k4KBLBJh/terrain.png'; // Tileset

  image.onload = () => {
    const {naturalWidth, naturalHeight} = image;
    
    const tileWidth = image.naturalWidth / 9;
    const tileHeight = image.naturalHeight / 28;
      
    console.log({
      tileWidth, 
      tileHeight,
      naturalWidth, 
      naturalHeight,
    })
      
    for (let column = 0; column < tilesAcross; column++) {
      for (let row = 0; row < tilesAcross; row++) {
        ctx.drawImage(
          image, // Image elemnt
          randomIntFromInterval(0, 5) * tileWidth, // sx - The x-axis of top left corner of the rect of the image to draw into context.
          randomIntFromInterval(0, 5) * tileHeight, // sy - The y-axis of top left corner of the rect of the image to draw into context.
          tileWidth, // sWidth - The width of the rect of the image to draw into context.
          tileHeight, //  sHeight - The height of the rect of the image to draw into the destination context.
          row * 32, // dx - The x-axis coordinate in the canvas at which to place the top-left corner of the image.
          column * 32, // dy - The y-axis coordinate in the canvas at which to place the top-left corner of the image.
          32, // dWidth - The width to draw the image in the canvas. This allows scaling of the drawn image.
          32 // dHeight- The width to draw the image in the canvas. This allows scaling of the drawn image.
        );
      }
    }
  };
}
canvas {
  background: black;
}
<div id="app"></div>

<style src="./style.css"></style>

【讨论】:

  • 添加一行解释由于它们不落在整数坐标上,它们将无法从中获得干净的精灵(半像素不存在),这将很有用。所以你的解决方案不是真正的好人,最好生成一张新地图。
  • 谢谢 - 不知道我的瓷砖集发生了什么,但看起来确实是这样......
  • @Thomas 我知道发生了什么。 postimg 处理器降低了图块的质量
猜你喜欢
  • 1970-01-01
  • 2013-01-12
  • 2017-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多