【问题标题】:Click detection in a 2D isometric grid?二维等距网格中的点击检测?
【发布时间】:2011-04-10 13:16:17
【问题描述】:

我从事网络开发已有多年,我正在慢慢参与游戏开发,对于我当前的项目,我有这张等距地图,我需要使用算法来检测哪个领域正在点击。顺便说一句,这一切都在带有 Javascript 的浏览器中。

地图
它看起来像this,我添加了一些数字来向您展示字段(图块)及其 ID 的结构。所有字段都有一个中心点(x,y 数组),绘制时四个角都基于该中心点。
如您所见,它不是菱形,而是锯齿形地图并且没有角度(自上而下的视图),这就是为什么考虑到所有文章和计算通常都基于菱形,我自己找不到答案的原因有一个角度。

数字
这是一张动态地图,所有大小和数字都可以更改以生成新地图。
我知道这不是很多数据,但地图是根据地图和字段大小生成的。
- 地图大小:x:800 y:400
- 字段大小:80x80(角落之间)
- 所有字段的中心位置 (x,y)

目标
提出一种算法,告诉客户端(游戏)在任何给定事件(点击、移动等)中鼠标位于哪个字段。

免责声明
我确实想提一下,我自己已经提出了一个可行的解决方案,但是我 100% 肯定它可以用更好的方式编写(我的解决方案涉及很多嵌套的 if 语句和循环),那就是为什么我在这里问。

Here's 我的解决方案示例,我基本上在最近的 4 个已知位置找到一个有角的正方形,然后根据两个最近字段之间的最小正方形得到我的结果。这有意义吗?

问我是否遗漏了什么。

【问题讨论】:

  • 等一下……你是说图中图形的角不相邻?
  • @albert 如果您的意思是所有单元格是否相互接触,那么是的,但如果您要问地图之外是否还有更多,那么没有。我发布的图片显示了确切的地图大小,无需任何滚动。
  • 嗯,它是菱形地图的子集。您可以使用稀疏数组并只剪掉角落,或者您不打算使用的任何东西吗?
  • 当然,还要将网格坐标旋转 45 度。
  • 问题是,我不会在任何时候旋转。我有一个包含所有单元格位置(中心点)的数组,并且基本上知道每个单元格的大小。我的图像显示了单元格的形状,但它们实际上并不存在于游戏中,并且除了中心点之外没有使用。

标签: javascript click 2d detection isometric


【解决方案1】:

这就是我想出的,

function posInGrid(x, y, length) {
xFromColCenter = x % length - length / 2;
yFromRowCenter = y % length - length / 2;
col = (x - xFromColCenter) / length;
row = (y - yFromRowCenter) / length;
if (yFromRowCenter < xFromColCenter) {
    if (yFromRowCenter < (-xFromColCenter))--row;
    else++col;
} else if (yFromRowCenter > xFromColCenter) {
    if (yFromRowCenter < (-xFromColCenter))--col;
    else++row;
}
return "Col:"+col+", Row:"+row+", xFC:"+xFromColCenter+", yFC:"+yFromRowCenter;
}

X 和 Y 是图像中的坐标,长度是网格的间距。

现在它返回一个字符串,只是为了测试..结果应该是行和列,这些是我选择的坐标:你的瓦片1有坐标(1,0)瓦片2是(3,0)瓦片10 是 (0,1),瓷砖 11 是 (2,1)。您可以在一两行中将我的坐标转换为您编号的图块。

还有一个用于测试的 JSFiddle http://jsfiddle.net/NHV3y/

干杯。

编辑:更改了返回语句,保留了一些我用于调试的变量。

【讨论】:

  • 酷,我昨晚没能把它翻译成 JavaScript,经过一段时间的仔细研究后,我的大脑有点放弃了。这很有趣。
  • @Albert 没问题,玩它很有趣。如果您认为它解决了您的问题,请记住接受答案。
  • @jcane86 这是您在此处发布的一个非常有趣的方法。明天我会看看它并测试它是否适用于我的情况(并且可能会在需要时在这里和那里添加一些小改动)。非常感谢
  • @Dennis 嘿,如果您不接受答案,您至少可以让我们知道结果如何。你解决问题了吗?您是否使用了答案中指出的任何解决方案?
  • @jcan86 抱歉,我马上就去度假了,所以没能跟进这个问题。我还没有测试过这个脚本,但它似乎确实可以在 jsfiddle 上运行,所以我认为这是正确的答案(至少对于我的问题,它是否适合我的项目)
【解决方案2】:

我过去使用的一种像素完美的命中检测方法(在 OpenGL 中,但概念也适用于此)是对场景进行离屏渲染,其中不同的对象用不同的颜色标识。

这种方法需要双倍的内存和双倍的渲染,但任意复杂场景的命中检测是通过简单的颜色查找完成的。

由于您想检测网格中的单元格,因此可能有更有效的解决方案,但我想提及这个是因为它的简单性和灵活性。

【讨论】:

  • 感谢您的回答,但我可能应该提到这些单元格不是对象,也不是这样生成的。但是我确实使用缓冲区来检测游戏中正常对象的点击,但不适用于单元格,因为它们在游戏中基本上不存在(对象对齐除外)
  • 我不明白这如何使这种方法无效。如果网格是静态的就更好了,你可以多设置一个缓冲区来检测单元格命中 - 你只需要渲染一次缓冲区。
  • 问题不在于缓冲区。您的方法的问题在于,游戏中根本没有单元格,除了对齐的其他对象并不总是存在。线条(网格)基本上只是线条,在那里向您展示单元格。它们没有填充任何精灵或颜色。如果这就是你的意思,我是否必须在缓冲区中使用单元格形状的精灵/纹理?
  • 我希望有一个数学解决方案。
  • 正如我所说,可能有更有效的解决方案。但是在这种情况下,数学解决方案只会提高内存效率,它不能满足简单的颜色查找。屏幕外缓冲区(与屏幕缓冲区相同的分辨率)需要用唯一的纯色渲染每个单元格,并且您需要分别在这些颜色和单元格标识符之间建立映射。当您在屏幕缓冲区上读取鼠标位置时,然后检查屏幕外缓冲区上这些坐标处的颜色并将其映射到您的单元格标识符。
【解决方案3】:

这个问题之前已经解决了,让我查阅一下我的笔记……

这里有一些很好的资源:

From Laserbrain Studios, The basics of isometric programming

Useful article in the thread posted here, in Java

如果这有帮助,请告诉我,祝你的游戏好运!

此代码在给定不均匀间距的情况下计算网格中的位置。应该很快;几乎所有的操作都是在数学上完成的,只使用一个循环。稍后我会思考问题的另一部分。

def cspot(x,y,length):
    l=length
    lp=length+1
    vlist = [ (l*(k%2))+(lp*((k+1)%2)) for k in range(1,y+1) ]
    vlist.append(1)
    return x + sum(vlist)

【讨论】:

  • 感谢您的评论,但不幸的是,这些文章(以及许多其他文章)基于菱形地图,而我的不是(如果您查看图片),这让我头晕目眩尝试进行这些计算时。
  • 我不小心投了反对票,这并没有让我反对。诚挚的歉意
  • 不,不是。
猜你喜欢
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 2020-05-03
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多