将屏幕坐标转换为等角地图坐标

4
我正在使用菱形模式生成等距视角的瓦片地图:
tileWidth = 128;
tileHeight = 94;

for (var x = 0; x < rows; x++) {
  for (var y = 0; y < cols; y++) {
    var screenX = (x - y) * tileWidthHalf;
    var screenY = (x + y) * tileHeightHalf;
    drawTile(screenX, screenY);
  }
}

这段代码显示正常,但我现在遇到了将屏幕坐标(鼠标位置)转换回等角线坐标的问题。

我尝试了反向计算:

var x = _.floor(screenY / (tileWidth / 2) - (screenX / tileWidth / 2));
var y = _.floor(screenY / (tileHeight / 2) + (screenX / tileHeight / 2));

对于0, 0的瓷砖,它可以正常工作,但在此后无法产生正确的值。

我只是无法想出正确的数学方法 - 我是否错过了一些微不足道的东西或者我对这个过程完全错误?


未来的访客:Nico的解决方案(被接受的解决方案)是我在互联网上找到的许多不同解决方案中唯一有效的。我正在遵循文章http://clintbellanger.net/articles/isometric_math/ - 您必须像Nico的答案中建议的那样用(screenX-tileWidthHalf)替换screenX。请参见我的评论在Nico的答案中。一定要向下取整结果。 - shell
Nico的解决方案是正确的,但请记住,您必须使用浮点数来表示screenx、screeny、tileWidthHalf和tileHeightHalf,否则精度不够。我之前使用整数,结果并不正确。将它们更改为浮点数后,它完美地工作了。 - chewinggum
2个回答

5

我不明白你是如何得出这个解法的。你需要解决方程组,得到以下解法:

x = 0.5 * ( screenX / tileWidthHalf + screenY / tileHeightHalf)
y = 0.5 * (-screenX / tileWidthHalf + screenY / tileHeightHalf)

如果你需要平铺索引,请在代码中使用floor函数。
我只能猜测你在坐标系中的图块对齐方式。但是从你在评论中发布的截图来看,我认为你需要交换screenX(screenX - tileWidthHalf)来获得准确的值。

我已经为了更容易调试而标记了这些瓦片,但是改变锚点并没有起到任何帮助。https://puu.sh/rpOic/2782995e22.png - 瓦片0,0的左半部分报告为-1,0,右半部分是正确的。瓦片1,0的左半部分报告为-1, 1,中间报告为1, 0,右边报告为1, 2 - helion3
不知何故,除非您使用非标准坐标系,否则此图像与您的公式不匹配。您的代码表明原点在左上角,x轴指向右上方,y轴指向右下方。您尝试过去掉四舍五入并查看所得到的值吗?我假设瓷砖是沿着两个轴的正方向绘制的。 - Nico Schertler
1
我已更新新代码的解决方案。啊,我刚看到这正是来自博客文章的解决方案。如果只针对一部分瓷砖有效,那么它可能是关键点或者四舍五入的问题。但由于你没有提及任何相关信息,我无法确定具体的错误所在。 - Nico Schertler
1
这是由于您的绘图与坐标系统不匹配。您只需要记住,瓷砖的位置实际上并不在瓷砖中。 - Nico Schertler
非常好的答案。在众多提供的解决方案中,这是唯一一个能够给出准确结果的答案。对于那些正在阅读文章:http://clintbellanger.net/articles/isometric_math/ 的人来说,你必须像Nico建议的那样将screenX更改为(screenX-tileWidthHalf)。不要使用该文章中提供的答案,而是使用Nico的答案。然后x是:x = 0.5 *((screenX-tileWidthHalf)/ tileWidthHalf + screenY / tileHeightHalf); 然后y是:0.5 *(-(screenX-tileWidthHalf)/ tileWidthHalf + screenY / tileHeightHalf); - shell
显示剩余5条评论

2

我将使用w表示tileWidth,使用h表示tileHeight。使用这种符号表示法,您基本上有

screenX = (x - y)*(w/2) = (w/2)*x + (-w/2)*y
screenY = (x + y)*(h/2) = (h/2)*x + (h/2)*y

这是一种线性变换,您也可以用矩阵符号来表示它:
⎛x⎞ ↦ ⎛w/2 -w/2⎞ ⎛x⎞
⎝y⎠   ⎝h/2  h/2⎠ ⎝y⎠

要撤销此操作,您需要反转它。有一个简单的公式用于2×2矩阵的逆运算。交换左上和右下条目。否定其他两个。将所有内容除以行列式。使用这个就可以得到逆变换:
⎛x⎞ ↦ 2/ ⎛ h/2 w/2⎞ ⎛x⎞ = ⎛ 1/w 1/h⎞ ⎛x⎞
⎝y⎠   wh ⎝-h/2 w/2⎠ ⎝y⎠   ⎝-1/w 1/h⎠ ⎝y⎠

因此,在您的符号表示中,您会得到

x = screenY / tileHeight + screenX / tileWidth
y = screenY / tileHeight - screenX / tileWidth

基本上这也是Nico写的。将非整数坐标转换为整数取决于您为每个瓷砖放置参考点的位置。


简单是一个相对的概念,我需要一点时间来理解它。 - helion3
@MvG,您能否解释一下您是如何找到变换矩阵的? - DRz
1
@DRz,我扩展了我的答案,以使该步骤更清晰明了。 - MvG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接