等距交错地图:计算屏幕上点的地图坐标


12

我知道已经有很多相关资源,但是我还没有找到与我的坐标系相匹配的资源,因此在调整这些解决方案以满足我的需求时遇到了很大的麻烦。我了解到,做到这一点的最佳方法是使用转换矩阵。实现这没问题,但是我不知道我必须以哪种方式变换坐标空间。

这是显示我的坐标系的图像:

在此处输入图片说明

如何将屏幕上的点转换为此坐标系?



我看不出这有什么帮助。我想您不太了解我的意思。
克里斯

它会进行转换,反之亦然,因此您需要将其反转。
Markus von Broady 2012年

Answers:


23

首先,这里是代码。解释如下:

/*
 * tw, th contain the tile width and height.
 *
 * hitTest contains a single channel taken from a tile-shaped hit-test
 * image. Data was extracted with getImageData()
 */

worldToTilePos = function(x, y) {

    var eventilex = Math.floor(x%tw);
    var eventiley = Math.floor(y%th);

    if (hitTest[eventilex + eventiley * tw] !== 255) {
        /* On even tile */

        return {
            x: Math.floor((x + tw) / tw) - 1,
            y: 2 * (Math.floor((y + th) / th) - 1)
        };
    } else {
        /* On odd tile */

        return {
            x: Math.floor((x + tw / 2) / tw) - 1,
            y: 2 * (Math.floor((y + th / 2) / th)) - 1
        };
    }
};

请注意,对于您问题中显示的地图,此代码开箱即用。这是因为您的奇数图块向左偏移,而奇数图块通常向右偏移(与平铺的地图编辑器一样)。您应该能够通过调整在奇数分位数情况下返回的x值来轻松解决此问题。

说明

这似乎是完成此任务的一种蛮力方法,但它至少具有像素完美且灵活性更高的优点。

诀窍在于查看地图时,不要将地图视为单个交错的网格,而应将两个网格相互叠加。有奇数行网格和偶数行网格,但让我们将它们称为红色和绿色,以便我们可以创建漂亮的图表。

红色和绿色两个网格

请注意,在该图像的右侧,我用紫色点标记了一个点。这是我们将尝试在原始图块空间中找到的示例点。

关于世界上任何一点的注意事项是,它总是始终恰好位于两个区域中-一个红色区域和一个绿色区域(除非它在边缘上,但是无论如何您都可能会在锯齿状的边缘边界内裁剪)。让我们找到那些地区...

两个候选区域

现在选择两个区域中的哪个区域是正确的区域。永远只有一个答案。

从这里开始,我们可以做一些更简单的算术运算,得出从采样点到两个区域的每个中心点的平方距离。以最接近者为准。

但是,还有另一种方法。对于每个测试区域,我们对与图块的确切形状匹配的位图进行采样。我们在转换为该单块的本地坐标的一点上对其进行采样。对于我们的示例,它看起来像这样:

点样

左边的一个,我们检查绿色区域并得到一个命中(黑色像素)。在右侧,我们测试红色区域并得到未命中(白色像素)。第二项测试当然是多余的,因为它将始终恰好是一个或另一个,而不是两者都做。

然后我们得出的结论是,我们在1,1的奇数区块中有命中。对于奇数行和偶数行,使用不同的转换,此坐标应易于映射到原始图块坐标。

此方法还允许您在像素测试位图上具有简单的每个像素属性。例如,白色是不透明的,黑色是亮色,蓝色是水,红色是固体。


2
太棒了³!
HumanCatfood 2013年

神奇且经过充分解释的答案-现在只需将其实现为代码即可。由于原始海报未提供任何有关其背后代码或语言的信息,除了Javascript中的标记外,我说一个A *答案
Tom'Blue'Piddock 2013年

1

我认为您遇到的问题是坐标空间。您提供给图块的坐标实际上不是等轴测投影-您需要将xAxis视为对角线向右下方,将yAxis视为对角线向左下方(或该坐标的某些变体)

现在,如果您沿图示的坐标轴移动,您将在“平铺空间”中沿对角线方向移动,因此正方形最终会变成菱形(并且一切都会更加复杂)

您要查找的转换矩阵是基于这些x和y轴构建的。它实际上与以下计算相同。

screenOffsetXY = screenPointXY - tileOriginXY;
tileX = dot(screenOffsetXY, xAxis) / tileWidth;
tileY = dot(screenOffsetXY, yAxis) / tileWidth;

编辑:我只是遇到了一个类似的问题(但我正在谈论的坐标系),有人在这里给出了更全面的答案:

如何将鼠标坐标转换为等距索引?


0

基本上,您想使用事件侦听器获取鼠标在窗口中的位置,您需要从鼠标位置中删除窗口中画布位置的偏移,因此鼠标位置是相对于画布的。

function mouseTwoGridPosition(e){

var mousex = e.pageX; //mouse position x
var mouseY = e.pageY;  //mouse position y
var canvas_width = 1000; //pixels
var offset_left = 100; //offset of canvas to window in pixels
var offset_top = 150; //offset of canvas to window in pixels

var isotile = 64; //if iso tile is 64 by 64

//get mouse position relative to canvas rather than window
var x = mousex - canvas_width/2 - offset_left;
var y = mousey - offset_top;


//convert to isometric grid
var tx = Math.round( (x + y * 2) / isotile) - 1;
var ty = Math.round((y * 2 - x) / isotile) - 1;

 //because your grid starts at 0/0 not 1/1 we subtract 1 
 // this is optional based on what grid number you want to start at



   return [tx,ty];
}

我将假设您知道如何在mousemove上的画布上进行事件监听,否则在考虑等距游戏设计之前,您可能想了解更多JS:D


这不是太简单了吗?我希望它完全匹配iso平铺的形式。如果我正确理解,您只是在检查一个矩形区域。
克里斯

您所说的等价物的“形式”是什么意思...例如,说您的鼠标在0:1的菱形边界内,则返回值为0:1,直到您的鼠标离开该边界。如果您的图块大小不同-那么我的方法将不起作用。提供的功能是我使用的,对我来说很好用。
戴夫

只是想知道,因为所有其他解决方案都更加复杂。当然,瓷砖的尺寸是一样的,所以我会检查一下。
克里斯

进行适当的修补,确保您获得正确的画布左上角和右上角偏移-以及画布宽度,当您进行数学运算时,它会很好地工作(以及等分点尺寸的宽度)。
戴夫

您确定使用与我相同的坐标系吗?它仍然完全关闭。
克里斯(Chris

0

我通过更改坐标空间解决了这个问题。现在,它开始在第一行中没有偏移,为此,我找到了一个可以稍作调整的工作示例。

    hWidth = this.tileset.tileSize.width / 2;
    hHeight = this.tileset.tileSize.height / 2;

    pX = point.x - halfWidth;
    pY = point.y - halfHeight;

    x = Math.floor((pX + (pY - hHeight) * 2) / this.tileset.tileSize.width);
    y = Math.floor((pY - (pX - hWidth) * 0.5) / this.tileset.tileSize.height);

    tx = Math.floor((x - y) / 2) + 1 + this.camera.x;
    ty = y + x + 2 + this.camera.y;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.