计算六边形网格上的距离

时间:2013-01-23 23:40:40

标签: hexagonal-tiles

我要做的是找出六角网格上两点之间有多少个六边形。我尝试在线搜索公式,但我找不到与我正在使用的十六进制网格类型相匹配的公式。

六角网格的布局与此坐标系相同:http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=1962

我知道这个坐标系可能无法做到这一点,但在我回去改变它之前,这是最后的努力。 非常感谢你提前。

8 个答案:

答案 0 :(得分:6)

如果您使用了一个沿两个方向沿着六边形纹理的坐标系,您可以使用:

distance = max(
     abs(dest.y - start.y),     
     abs(dest.x - start.x),
     abs((dest.x - dest.y)*-1 - (start.x - start.y)*-1)
)

然而你没有,你正在使用一个波浪形的坐标系统,它只沿一个方向(水平)与颗粒一起。幸运的是,我们可以使用

在两者之间进行转换
straight.y = squiggle.y
straight.x = ciel(squiggle.y / -2) + squiggle.x

因此,使用这个方程组求解距离可以得到:

distance = max(
     abs(dest.y - start.y),     
     abs(ceil(dest.y / -2) + dest.x - ceil(start.y / -2) - start.x),
     abs(-dest.y - ceil(dest.y / -2) - dest.x + start.y  + ceil(start.y / -2) + start.x)
)

这将使用他们的坐标获得两个六边形之间的曼哈顿距离(假设我没有进行任何拼写转换x和y,因为你的网格从我的旋转了90度)。但是你必须为我的中学代数老师买一块饼干才能工作,否则我就搞乱了分配财产。

注意:可能需要摆弄负坐标,我没有检查。

答案 1 :(得分:5)

感谢@ user2709663和@jonathankoren提供答案。我花了很多时间来回答你的问题,但发现这两方面都存在一些问题。或者至少没有明确说明为这些答案考虑的网格类型。但是,我找到了一个非常好的教程和这个问题的代码实现,以及一个用于管理十六进制网格的库:http://www.redblobgames.com/grids/hexagons/(库代码:http://www.redblobgames.com/grids/hexagons/implementation.html)。我还为“odd-q”垂直布局实现了matlab版本的距离代码,如下所示:

function f = offset_distance(x1,y1,x2,y2)
    ac = offset_to_cube(x1,y1);
    bc = offset_to_cube(x2,y2);
    f = cube_distance(ac, bc);
end

function f = offset_to_cube(row,col)
    %x = col - (row - (row&1)) / 2;
    x = col - (row - mod(row,2)) / 2;
    z = row;
    y = -x-z;
    f = [x,z,y];
end

function f= cube_distance(p1,p2)
    a = abs( p1(1,1) - p2(1,1));
    b = abs( p1(1,2) - p2(1,2));
    c = abs( p1(1,3) - p2(1,3));
    f =  max([a,b,c]);
end

这是一个matlab测试代码

sx = 6;
sy = 1;
for i = 0:7
    for j = 0:5
        k = offset_distance(sx,sy,i,j);
        disp(['(',num2str(sx),',',num2str(sy),')->(',num2str(i),',',num2str(j),')=',num2str(k)])
    end
end

答案 2 :(得分:2)

找到两个六边形之间的最短路径:

  1. 从一个十六进制开始,
  2. 在不同的行上,沿着对角线朝向另一行。
  3. 在同一行上,直奔另一个十六进制。
  4. 让我们调用x方向dx的差异和y方向的差异dy。如果dy / 2 > dx,您不必执行第二步,因此距离只是dy。否则,距离为dy + (dx - dy / 2)。除非我弄错了。

答案 3 :(得分:2)

The accepted answer不正确。当我提到在非正交轴上使用正交坐标时,我最初对它持怀疑态度,但是根据我自己的解决方案运行代码表明距离化合物的过度估计。

实际正确的解决方案是:

def hexDistance(start, dest):
  if (start.x == dest.x):
    return abs(dest.y - start.y)
  elif (start.y == dest.y):
    return abs(dest.x - start.x)
  else:
    dx = abs(dest.x - start.x)
    dy = abs(dest.y - start.y)
    if start.y < dest.y:
      return dx + dy - int(math.ceil(dx / 2.0))
    else:
      return dx + dy - int(math.floor(dx / 2.0))

这使用hex-&gt; square表示:

        ------        
 ------  0, +1 ------ 
 -1, +1 ------ +1, +1  
 ------  0,  0 ------ 
 -1,  0 ------ +1,  0  
 ------  0, -1 ------ 
        ------        

 --------------------------
| -1, +1 |  0, +1 | +1, +1 |
|--------------------------
| -1,  0 |  0,  0 | +1, 0  |
|--------------------------|
|        |  0, -1 |        |
 -------------------------- 

答案 4 :(得分:2)

M H Rasel在之前的回答中将这篇文章联系起来:Hexagonal Grids。在这篇优秀文章之后,我发现我需要立方体坐标;这提供了计算距离的最简单方法。以下是Kotlin的代码片段:

data class Point(val x: Int, val y: Int, val z: Int) {

    fun distance(b: Point): Int {
        return (abs(x - b.x) + abs(y - b.y) + abs(z - b.z)) / 2
    }

}

var x = 0
var y = 0
var z = 0

val p1 = Point(x, y, z)    // starting position

val steps = "ne,ne,ne".split(",")    // go to North-East 3 times

for (direction in steps) {
    when(direction) {
        "n"  -> { ++y; --z }
        "ne" -> { ++x; --z }
        "se" -> { ++x; --y }
        "s"  -> { --y; ++z }
        "sw" -> { --x; ++z }
        "nw" -> { ++y; --x }
    }
}

val p2 = Point(x, y, z)    // we arrived here
val dist = p1.distance(p2)    // the result is here (in this example: 3)

编辑:我假设是一个平顶六角网格。

答案 5 :(得分:0)

这是次优的,但不是TOO次优(应该是O(n))算法:

首先,创建一个函数,确定十六进制网格中某个位置的六边形是否与具有特定起点和终点的线段相交(例如,计算由它组成的六条线并执行类似的操作:http://alienryderflex.com/intersect/。)

其次,创建一个函数,确定一个点所在的十六进制网格上的六边形。

现在,写下你的算法:

  • 保留目前为止线段重叠的所有六边形的列表
  • 从线段开头的六边形开始
  • 对于最近重叠的六边形,如果它不在列表中,请查看lin segmente是否与该六边形相交。如果是这样,请将其作为列表的新头并重复
  • 如果我们用完六边形进行测试,请返回我们制作的列表

我建议您测试线段与六边形之间的接缝完全平行并沿着六边形之间的接缝运行的情况,以查看是否在一侧,两侧或两者都得到六边形(从而停止)。

答案 6 :(得分:0)

如果网格上的图块可能会被阻挡,那么您对A *(或A-Star)迷宫解算算法感兴趣: http://labs.makemachine.net/2010/03/a-star-maze-solver/

此视频中使用的机制适用于正方形网格,但几乎没有任何额外编码可以将其应用于六边形网格。 对于每个图块,解算器知道接下来要尝试哪些图块,因为图块存储指向其周围图块的指针。在正方形网格中,每个图块最多存储4个指针(最大,因为它们只存储指向未阻塞图块的指针),而您的情况唯一的区别是存储最多6个指针。 / p>

如果瓷砖总是可以穿越,那么A *仍然可以完成工作,但是可能有更快的方法。如果我正确地解释你的问题你不是在远处感兴趣,而是在两个给定的十六进制之间的十六进制数的整数计数?请尝试以下方法:

class Coord {
    int x;
    int y;
}

int dist(Coord hex1, Coord hex2) {
    int xSteps = Math.abs(hex1.x - hex2.x);
    int ySteps = Math.abs(hex1.y - hex2.y);

    return Math.max(xSteps, ySteps) + Math.abs(xSteps - ySteps);
}

为什么你会问?这个问题是关于确定我们必须移动垂直水平多少次而不是对角。我们希望尽可能地沿对角线移动,否则我们对距离感觉并不聪明。 Math.abs(xSteps - ySteps)是我们必须进行的非对角线移动的数量。再加上x和y的距离越大,你就完成了。

答案 7 :(得分:0)

如果您的六边形平铺有方向:N,NE,SE,S,SW,NW,如Advent of Code 2017 problem 11,并且您将目标偏移到(0,0)(通过预先从目标减去您的位置)以下逻辑对我有用:

def distance(self):
    # Take diagonal steps towards self.x == 0
    steps = abs(self.x)
    # y moves closer to 0 by steps because moving diagonal, but never moving too far
    if self.y > 0:
        # Might still be positive, but never negative
        y = max(self.y - steps, 0)
    else:
        # Might still be negative, but not positive
        y = min(self.y + steps, 0)
    # You move 2 positions north/south by a single move so divide y's by 2
    return abs(y) // 2 + abs(steps)

我认为通过切换x和y的角色,它可能适用于方向为EAST和WEST的十六进制网格,而不是类似于您的南方和南方。在这种情况下,你会转向self.y == 0对角线(如果需要)等。

相关问题