鼠标位置到等高的瓷砖,包括高度 [英] mouse position to isometric tile including height

查看:79
本文介绍了鼠标位置到等高的瓷砖,包括高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Struggeling将鼠标的位置转换为网格中tile的位置。当它完全平坦时,数学看起来像这样:

  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是贴片的大小。然后,位置包含我正在悬停的图块的网格坐标。这在平坦表面上工作得相当好。





现在我正在添加高度,数学没有考虑到这一点。





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



我不知道如何确定我在哪个瓷砖上空盘旋。



编辑



取得一些进展...之前,我依赖在mouseover事件上计算网格位置。我只是将其更改为在绘制循环本身中进行计算,并检查坐标是否在当前绘制的图块的限制范围内。创造了一些头顶的东西,不确定我是否对它非常满意,但我会确认它是否有效。



编辑2018:



我没有答案,但是因为这个ha [sd]是一个开放的赏金,请自己帮助一些



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

函数getTilesInColumn(columnNo,width,height){
let startTileX = 0,startTileY = 0;
让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;
}
返回tilesInColumn;
}



第2步



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



  function getTileYIncrementByTileZ(tileZ){
//在这里实现
return 0;
}

函数findExactTile(mouseX,mouseY,tilesInColumn,tiles2d,
firstTileXShiftAtScreen,firstTileYShiftAtScreenAt0Height,
tileWidth,tileHeight){
//我们建了一个底部出现的瓦片组
//从下到上迭代瓦片
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 !!!
返回tileInfo;
}
}
}

函数findABForTopLineOfTile(tileX,tileY,tileZ,isLeftTopLine,tileWidth,tileHeight){
//找到一条顶线〜 ~~ a,b
// y = a * x + b;
让a = tileWidth / tileHeight;
if(isLeftTopLine){
a = -a;
}
让b = isLeftTopLine?
tileY * 2 * tileHeight:
- (tileX + 1)* 2 * tileHeight;
b - = getTileYIncrementByTileZ(tileZ);
返回{a:a,b:b};
}


Struggeling translating the position of the mouse to the location of the tiles in my grid. When it's all flat, the math looks like this:

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));

where pos.x and pos.y are the position of the mouse, 240 and 320 are the offset, 24 and 48 the size of the tile. Position then contains the grid coordinate of the tile I'm hovering over. This works reasonably well on a flat surface.

Now I'm adding height, which the math does not take into account.

This grid is a 2D grid containing noise, that's being translated to height and tile type. Height is really just an adjustment to the 'Y' position of the tile, so it's possible for two tiles to be drawn in the same spot.

I don't know how to determine which tile I'm hovering over.

edit:

Made some headway... Before, I was depending on the mouseover event to calculate grid position. I just changed this to do the calculation in the draw loop itself, and check if the coordinates are within the limits of the tile currently being drawn. creates some overhead tho, not sure if I'm super happy with it but I'll confirm if it works.

edit 2018:

I have no answer, but since this ha[sd] an open bounty, help yourself to some code and a demo

The grid itself is, simplified;

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

which leads to a drawing like:

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
    }
}

edit post-bounty:

See GIF. The accepted answer works. The delay is my fault, the screen doesn't update on mousemove (yet) and the frame rate is low-ish. It's clearly bringing back the right tile.

Source

解决方案

Intresting task.

Lets try to simplify it - lets resolve this concrete case

Solution

Working version is here: https://github.com/amuzalevskiy/perlin-landscape (changes https://github.com/jorgt/perlin-landscape/pull/1 )

Explanation

First what came into mind is:

Just two steps:

  • find an vertical column, which matches some set of tiles
  • iterate tiles in set from bottom to top, checking if cursor is placed lower than top line

Step 1

We need two functions here:

Detects column:

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

Function which extracts an array of tiles which correspond to this column.

Rotate image 45 deg in mind. The red numbers are columnNo. 3 column is highlighted. X axis is horizontal

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;
}

Step 2

A list of tiles to check is ready. Now for each tile we need to find a top line. Also we have two types of tiles: left and right. We already stored this info during building matching tiles set.

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};
}

这篇关于鼠标位置到等高的瓷砖,包括高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆