javascript - 鼠标位置到等距图 block (包括高度)

标签 javascript canvas mouse noise isometric

很难将鼠标的位置转换为网格中图 block 的位置。当一切平坦时,数学看起来像这样:

this.position.x = Math.floor(((pos.y - 240) / 24) + ((pos.x - 320) / 48));
this.position.y = Math.floor(((pos.y - 240) / 24) - ((pos.x - 320) / 48));

其中 pos.x 和 pos.y 是鼠标的位置,240 和 320 是偏移量,24 和 48 是图 block 的大小。然后,位置包含我悬停在其上的图 block 的网格坐标。这在平坦的表面上效果相当好。

/image/gp7qU.png

现在我要添加高度,但数学并未考虑这一点。

/image/jWGMf.png

该网格是一个包含噪声的 2D 网格,它被转换为高度和图 block 类型。高度实际上只是对图 block “Y”位置的调整,因此两个图 block 可以绘制在同一位置。

我不知道如何确定我将鼠标悬停在哪个图 block 上。

编辑:

取得了一些进展...之前,我依靠鼠标悬停事件来计算网格位置。我只是更改了它以在绘制循环本身中进行计算,并检查坐标是否在当前正在绘制的图 block 的限制内。虽然会产生一些开销,但不确定我是否对此非常满意,但我会确认它是否有效。

编辑 2018 年:

我没有答案,但由于这是一个开放的赏金,请自行获取一些code and a demo

网格本身被简化;

let grid = [[10,15],[12,23]];

这会导致这样的绘图:

for (var i = 0; i < grid.length; i++) {
    for (var j = 0; j < grid[0].length; j++) {
        let x = (j - i) * resourceWidth;
        let y = ((i + j) * resourceHeight) + (grid[i][j] * -resourceHeight); 
        // the "+" bit is the adjustment for height according to perlin noise values
    }
}

编辑赏金后:

参见 GIF。接受的答案有效。延迟是我的错,屏幕在鼠标移动时还没有更新,而且帧速率很低。很明显,它带回了正确的瓷砖。

enter image description here

Source

最佳答案

有趣的任务。

让我们尝试简化它 - 让我们解决这个具体案例

解决方案

工作版本在这里:https://github.com/amuzalevskiy/perlin-landscape (更改https://github.com/jorgt/perlin-landscape/pull/1)

说明

首先想到的是:

Step by step

只需两步:

  • 找到与某些图 block 组匹配的垂直列
  • 从下到上迭代集合中的图 block ,检查光标是否低于顶线

第 1 步

这里我们需要两个函数:

检测列:

function getColumn(mouseX, firstTileXShiftAtScreen, columnWidth) {
  return (mouseX - firstTileXShiftAtScreen) / columnWidth;
}

提取与此列对应的图 block 数组的函数。

将图像旋转 45 度。红色数字是columnNo。 3 列突出显示。 X轴是水平的

enter image description here

function tileExists(x, y, width, height) {
  return x >= 0 & y >= 0 & x < width & y < height; 
}

function getTilesInColumn(columnNo, width, height) {
  let startTileX = 0, startTileY = 0;
  let xShift = true;
  for (let i = 0; i < columnNo; i++) {
    if (tileExists(startTileX + 1, startTileY, width, height)) {
      startTileX++;
    } else {
      if (xShift) {
        xShift = false;
      } else {
        startTileY++;
      }
    }
  }
  let tilesInColumn = [];
  while(tileExists(startTileX, startTileY, width, height)) {
    tilesInColumn.push({x: startTileX, y: startTileY, isLeft: xShift});
    if (xShift) {
      startTileX--;
    } else {
      startTileY++;
    }
    xShift = !xShift;
  }
  return tilesInColumn;
}

第 2 步

要检查的图 block 列表已准备就绪。现在,对于每个图 block ,我们需要找到一条顶线。我们还有两种类型的图 block :左图和右图。我们已经在构建匹配图 block 集期间存储了此信息。

enter image description here

function getTileYIncrementByTileZ(tileZ) {
    // implement here
    return 0;
}

function findExactTile(mouseX, mouseY, tilesInColumn, tiles2d,
                       firstTileXShiftAtScreen, firstTileYShiftAtScreenAt0Height,
                       tileWidth, tileHeight) {
    // we built a set of tiles where bottom ones come first
    // iterate tiles from bottom to top
    for(var i = 0; i < tilesInColumn; i++) {
        let tileInfo = tilesInColumn[i];
        let lineAB = findABForTopLineOfTile(tileInfo.x, tileInfo.y, tiles2d[tileInfo.x][tileInfo.y], 
                                            tileInfo.isLeft, tileWidth, tileHeight);
        if ((mouseY - firstTileYShiftAtScreenAt0Height) >
            (mouseX - firstTileXShiftAtScreen)*lineAB.a + lineAB.b) {
            // WOHOO !!!
            return tileInfo;
        }
    }
}

function findABForTopLineOfTile(tileX, tileY, tileZ, isLeftTopLine, tileWidth, tileHeight) {
    // find a top line ~~~ a,b
    // y = a * x + b;
    let a = tileWidth / tileHeight; 
    if (isLeftTopLine) {
      a = -a;
    }
    let b = isLeftTopLine ? 
       tileY * 2 * tileHeight :
       - (tileX + 1) * 2 * tileHeight;
    b -= getTileYIncrementByTileZ(tileZ);
    return {a: a, b: b};
}

关于javascript - 鼠标位置到等距图 block (包括高度),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21842814/

相关文章:

javascript - Photoshop JavaScript 将图像和 Canvas 调整为特定(非正方形)大小

javascript - jquery 在 <div> 图形区域内设置鼠标位置

html - 使用 css 将鼠标滚轮设置为水平滚动

javascript - 在javascript中手动调用页面

javascript - 如何在没有 "wrapper: false"的情况下通过 brunch 访问包装到命名空间中的函数?

php - HTML5 canvas - 将保存的图像分享到社交媒体

javascript - HTML5-JS : Shoot Bullet From Facing Direction

javascript - 从 Google Chrome 开发者控制台调用 PrimeFaces

javascript - 条件 V-HTML 渲染

java - 在导航器中显示用户文件以进行拖放