基于轴坐标查询“周围六角形瓦片”

时间:2013-07-08 14:31:24

标签: sql algorithm

阅读Red Blob Games的优秀article on heaxgon tile maps and their coordinates

我想知道如何编写一个SQL查询,返回围绕居中区块的区块,范围为X.(假设文章中涵盖了“轴向坐标”)

我最初的一个简单想法是

WHERE x BETWEEN tile_x - 1 AND tile_x + 1 AND y BETWEEN tile_y - 1 AND tile_y + 1

但是这会产生太多的瓷砖,形成一个更像菱形而不是圆形的形状,这就是我所需要的。

不幸的是,我还没有找到一个确凿的答案,也许这里有人可以给我一个提示。

我已经考虑了坐标总和上的一些技巧,并且它们大于低于范围,但这对于轴坐标不起作用。

2 个答案:

答案 0 :(得分:1)

从链接文章的图表中可以看出类似

的内容
where (x between tile_x and tile_x + 1) and (y between tile_y - 1 and tile_y + 1)
or (x = tile_x - 1) and (y = tile_y)

应该有效

如果您希望在给定图块(tile_x, tile_y)的距离n内找到图块(x, y),则通过添加0.5来修改x坐标会更容易到与给定图块具有奇数距离的每一行的x坐标,以便增加对称性:

       -1.5 -0.5 0.5 1.5                                                   
      -2   -1   0   1   2                                                  
  -2.5 -1.5 -0.5 0.5 1.5 2.5                                               
 -3   -2   -1   0   1   2   3                                              
  -2.5 -1.5 -0.5 0.5 1.5 2.5                                               
      -2   -1   0   1   2                                                  
       -1.5 -0.5 0.5 1.5                                                   

这可以使用表达式tile_x + 0.5 * tile_y%2

来实现

当给定距离内的瓦片数量减少一个时 从行到行,给定的(修改的)x坐标的限制 行是n - abs(tile_y - y)/2

如果

,则瓷砖在距离n内
abs(tile_y - y) <= n                                                       
and abs(tile_x - x + 0.5 * (tile_y-y)%2) <= n - abs(tile_y - y)/2              

在sql中:

SELECT tile_x, tile_y                                                      
FROM tiles                                                                 
WHERE ABS(tile_y - y) <= n                                                 
AND ABS(tile_x - x +0.5*(tile_y-y)%2) + ABS(tile_y - y) / 2 <= n             

答案 1 :(得分:0)

经过多次阅读后,我发现我链接的文章实际上已经解决了这个问题,虽然有点隐藏,所以这里有一个更“直截了当”的答案。

(尽管如此,Terje D.的答案很好,我只是发布了这个,因为我觉得它比他的答案的“巫术”更容易理解)

article from Red Blob Games中,他实际上描述了计算两个给定十六进制之间距离的公式:

function hex_distance(Hex(q1, r1), Hex(q2, r2)) {
    return (abs(q1 - q2) + abs(r1 - r2)
          + abs(q1 + r1 - q2 - r2)) / 2;
}

我把它翻译成MySQL中的一个函数

CREATE FUNCTION `rangeBetweenTiles`(tile1q int, tile1r int, tile2q int, tile2r int) RETURNS int(11)
DETERMINISTIC
BEGIN
RETURN (abs(tile1q - tile2q) + abs(tile1r - tile2r) 
        + abs(tile1q + tile1r - tile2q - tile2r)) / 2;
END

在另一个函数中使用它:

CREATE FUNCTION `isInRange`(tile1q int, tile1r int, tile2q int, tile2r int, `range` Int) RETURNS tinyint(1)
DETERMINISTIC
BEGIN
RETURN rangeBetweenTiles(tile1q, tile1r, tile2q, tile2r) <= `range`;
END

然后可以在select语句中轻松使用它:

select *
from tiles
where isInRange(:tile_q, :tile_r, positionQ, positionR, :n)

它适用于任何:n