0

在阅读了 Red Blob Games关于六角瓷砖地图及其坐标的优秀文章之后。

我想知道如何编写一个 SQL 查询来返回围绕中心瓷砖的瓷砖,直到 X 范围内。(假设文章中涵盖了“轴坐标”)

我最初的一个简单想法是

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

但这会返回太多的瓷砖,以某种方式创建一个更像菱形而不是圆形的形状,这正是我所需要的。

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

我已经考虑过一些关于坐标总和的技巧,以及它们是否大于或低于范围,但这不适用于轴向坐标。

4

2 回答 2

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(tile_x, tile_y)一定距离内的图块,如果通过添加到与给定图块具有奇数距离的每一行的坐标来修改 x 坐标,则会更容易,从而增加对称性:n(x, y)0.5x

       -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

由于给定距离内的瓦片数量逐行减少 1 ,因此给定 行
中(修改的)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             
于 2013-07-08T19:17:15.353 回答
0

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

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

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

于 2013-07-09T15:38:33.553 回答