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

Jab*_*ook 3 .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
Run Code Online (Sandbox Code Playgroud)

在现实生活中看起来像是每个六边形的随机颜色:

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

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

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       
Run Code Online (Sandbox Code Playgroud)

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

我已经被困在这一个2天了,真的想弄明白.谢谢

Tyl*_*den 5

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

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

  • 此外,由于您只想找到最近的六边形,因此您应该能够省略平方根检查,因为实际长度不会用于任何事情.如果要检查大量多边形,这可能会节省一些周期.Tyler基于宽度的剔除点也是您应该考虑实施的非常快速的优化,并且绝对应该用作预测试. (3认同)

Ash*_*Ash 5

事实上,这可以很容易地在数学上完成,而无需诉诸于迭代大量潜在值的恼人的、规模限制的方法。我结合以下网站上的优秀信息想出了以下代码。秘密是想象你的六边形网格实际上是一个三维立方体的平面。

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

注意 SS2DCoords 和 SS3DCoords 是简单的结构,具有两个或三个整数变量,分别表示 2D 和 3D 网格上的坐标(x/y 表示 2D,x/y/z 表示 3D) 另请注意,我的六角网格从 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;
}
Run Code Online (Sandbox Code Playgroud)