我知道已经有很多相关资源,但是我还没有找到与我的坐标系相匹配的资源,因此在调整这些解决方案以满足我的需求时遇到了很大的麻烦。我了解到,做到这一点的最佳方法是使用转换矩阵。实现这没问题,但是我不知道我必须以哪种方式变换坐标空间。
这是显示我的坐标系的图像:
如何将屏幕上的点转换为此坐标系?
我知道已经有很多相关资源,但是我还没有找到与我的坐标系相匹配的资源,因此在调整这些解决方案以满足我的需求时遇到了很大的麻烦。我了解到,做到这一点的最佳方法是使用转换矩阵。实现这没问题,但是我不知道我必须以哪种方式变换坐标空间。
这是显示我的坐标系的图像:
如何将屏幕上的点转换为此坐标系?
Answers:
首先,这里是代码。解释如下:
/*
* 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的奇数区块中有命中。对于奇数行和偶数行,使用不同的转换,此坐标应易于映射到原始图块坐标。
此方法还允许您在像素测试位图上具有简单的每个像素属性。例如,白色是不透明的,黑色是亮色,蓝色是水,红色是固体。
我认为您遇到的问题是坐标空间。您提供给图块的坐标实际上不是等轴测投影-您需要将xAxis视为对角线向右下方,将yAxis视为对角线向左下方(或该坐标的某些变体)
现在,如果您沿图示的坐标轴移动,您将在“平铺空间”中沿对角线方向移动,因此正方形最终会变成菱形(并且一切都会更加复杂)
您要查找的转换矩阵是基于这些x和y轴构建的。它实际上与以下计算相同。
screenOffsetXY = screenPointXY - tileOriginXY;
tileX = dot(screenOffsetXY, xAxis) / tileWidth;
tileY = dot(screenOffsetXY, yAxis) / tileWidth;
编辑:我只是遇到了一个类似的问题(但我正在谈论的坐标系),有人在这里给出了更全面的答案:
基本上,您想使用事件侦听器获取鼠标在窗口中的位置,您需要从鼠标位置中删除窗口中画布位置的偏移,因此鼠标位置是相对于画布的。
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
我通过更改坐标空间解决了这个问题。现在,它开始在第一行中没有偏移,为此,我找到了一个可以稍作调整的工作示例。
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;