以六角形网格捕捉到最接近的六边形中心

时间:2014-03-04 18:44:44

标签: .net algorithm c++-cli rounding hexagonal-tiles

我正在尝试创建一个基于网格的游戏。到目前为止,我有一个基于六边形拼贴的网格,坐标方案如下所示:

col 0
 | col 1
 |   | col 2
 |   |  |
 __  | __    __    __    __   
/00\__/02\__/04\__/06\__/08\__
\__/01\__/03\__/05\__/07\__/09\--- row 0
/10\__/12\__/14\__/16\__/18\__/
\__/11\__/13\__/15\__/17\__/19\--- row 1
/20\__/22\__/24\__/26\__/28\__/
\__/21\__/23\__/25\__/27\__/29\--- row 2
/30\__/32\__/34\__/36\__/38\__/
\__/  \__/  \__/  \__/  \__/   --- row 3

在现实生活中看起来像这样,每个六边形都有随机颜色:

我正在努力弄清楚的是,当用户点击六边形时,我如何确定他们点击的六边形?

我到目前为止所尝试的代码如下:

private: System::Void MyForm_MouseDown(System::Object^  sender,
    System::Windows::Forms::MouseEventArgs^  e) {

    int CloseI=0,CloseJ=0;
    CloseJ = FindNearesetX(e->X);
    CloseI = FindNearesetY(e->Y);
    //Grid[down(y)][along(x)]
    P1.X = Grid[CloseI][CloseJ].GetX();
    P1.Y = Grid[CloseI][CloseJ].GetY();
} // END MOUSE DOWN EVENT

int FindNearesetX(int ActualX){
    int ClosestJPos;
    ClosestJPos = ((ActualX-Grid[0][0].GetX())/(1.5*HexSideLength));
    return ClosestJPos;
}//END FIND NEAREST X

int FindNearesetY(int ActualY){
    int ClosestIPos;
    ClosestIPos = ((ActualY-Grid[0][0].getY())/(HexHeight));
    return ClosestIPos;
}//END FIND NEAREST Y

private: System::Void MyForm_MouseMove(System::Object^  sender,
    System::Windows::Forms::MouseEventArgs^  e) {
    this->Invalidate();

    P2.X = e->X;
    P2.Y = e->Y; 
} // END MOUSE MOVE EVENT       

然而,这并不是我想要的,这是因为当用户点击六边形中心点的左侧时,它会抓到他们点击的那个左边的六边形,如果他们点击上面的六边形所有奇数列上的中心点都会捕捉到他们点击的六角形上方的六边形。

我现在已经被困在这个2天了,真的很想弄明白。 感谢

4 个答案:

答案 0 :(得分:5)

点击的点始终最接近发生咔嗒声的六边形中心,除非该点正好在两个六边形之间,在这种情况下,它将与两个中心等距。两点之间距离的等式是SQRT((x1-x2)^ 2 +(y1-y2)^ 2)。

您无需测试每个六边形的距离。通过创建x / y阈值,您可以将测试限制在附近的六边形。例如,如果六边形的宽度为10且点为(51,73),则不必测试x坐标为<六角形的六边形。 40或> 70。

答案 1 :(得分:3)

应该能够找到具有O(1)复杂度的最接近的六边形:

    odd     even    odd    even
 0 +----+  |    |  +----+  |
   | 00 |\ |    |  | 02 |  |
   |    | \+----+  |    |  +
   |    | /| 01 |  |    |  |
 H +----+/ |    |  +----+  |
   | 10 |\ |    |  | 12 |  |
   |    | \+----+  |    |  +
   |    | /| 11 |  |    |  |
2H +----+/ |    |  +----+  |
   0....X..W.......2W......3W

角落'+'也是六角形的角落。 'x'DIV 2 * W和y DIV H确定'x'mod W <1时的正确平方。 X.当W&lt; = x mod 2W&lt; = W + X时,该点位于偶数列上。在奇数列上,行号为 y DIV H ,在偶数列上,它是( y + H / 2)DIV H

用锯齿形图案表示不好的灰色区域需要求解两个线性方程(或点积)以确定该点落在对角线的哪一侧。在任何情况下,最多可以选择两个候选人。

答案 2 :(得分:0)

实际上,由于六边形的规则形状(所有边都是相同的长度),这就像在六边形瓷砖列表中循环并确定哪个瓷砖的中心最接近鼠标点击一样简单。

C ++伪代码:

//assuming "map" is an array of "Tile" pointers

Tile *closest = nullptr;
int fromClosestCenterToClick = INT_MAX;

for (int row = 0; row < map.numRows(); row++)
{
   for (int col = 0; col < map.numCols(); col++)
   {
      int distance = std::sqrt(std::pow(map[row][column]->center.x - mouseClickX, 2) + std::pow(map[row][column]->center.y - mouseClickY, 2) < fromClosestCenterToClick);
      if (distance < fromClosestCenterToClick)
      {
         closest = map[row][column];
         fromClosestCenterToClick = distance;
      }
   }
}
//closest now holds the correct tile

答案 3 :(得分:0)

事实上,这可以通过数学上非常容易地完成,而不需要采用刺激性的,限制尺度的方法来迭代大量的潜在价值。我想到了以下代码,并与以下网站上的优秀信息勾结。秘诀是想象你的六边形网格实际上是一个三维立方体的平面。

http://www.redblobgames.com/grids/hexagons/

N.B。 SS2DCoordinates和SS3DCoordinates是具有两个或三个整数变量的简单结构,分别表示2D和3D网格上的坐标(2D为x / y,3D为x / y / z)另请注意,我的十六进制网格从1/1而不是0开始/ 0。

SS2DCoordinates coordinatesForHexAtPoint(float a, float b)
{
    // Get basic hex information - pseudocode
    float radius = <radius of one hexagon>

    // Estimate the most likely hex and round to nearest values
    float x = 2.0/3.0*a/radius;
    float z = (1.0/3.0*sqrt(3.0)*b-1.0/3.0*a)/radius;
    float y = -x-z;

    int ix = (int)round((floor(x-y)-floor(z-x))/3.0);
    int iy = (int)round((floor(y-z)-floor(x-y))/3.0);
    int iz = (int)round((floor(z-x)-floor(y-z))/3.0);

    // Adjust to flat coordinates on the offset numbering system
    SS2DCoordinates corrected = hexToFlatCoordinates(SS3DCoordinatesMake(ix, iy, iz));
    corrected.x --;
    return axialToOffsetCoordinates(corrected);
}


SS2DCoordinates hexToFlatCoordinates(SS3DCoordinates hex)
{
    SS2DCoordinates coordinates;
    coordinates.x = hex.x;
    coordinates.y = hex.z;
    return coordinates;
}


SS2DCoordinates axialToOffsetCoordinates(SS2DCoordinates axial)
{
    SS2DCoordinates offset;
    offset.x = axial.x;
    offset.y = axial.y + (NSInteger)ceilf((float)axial.x/2.0);
    return offset;
}