Answers:
看看这张照片
如您所见,有一种相对直观的方法将x,y直角坐标系映射到六角形坐标系。
我们可以谈论“矩形”不规则六边形,即刻在椭圆上的六边形或从在两个方向上成比例缩放的正六边形获得的六边形(无旋转剪切)。
矩形可以由外接矩形的高度和宽度加上外接矩形的宽度来定义。(W,W,H)
找出六角形索引的最简单方法是按以下方式划分空间:
矩形宽度为w +(W-w)/ 2 =(w + W)/ 2,其高度为h / 2;绿色矩形的宽度为(Ww)/ 2。很容易找出该点落在哪个矩形中:
u和v是提示点,它指示点在i,j矩形中的位置:使用w可以说我们是否在绿色区域(u <(Ww)/ 2)中。
如果是这种情况,我们在绿色区域,我们需要知道我们是在六边形的上半部还是下半部:如果i和j均为偶数或均为奇数,则我们位于上半部。否则,我们处于下半部分。
在这两种情况下,对u和v进行变换都是有用的,因此它们在0到1之间变化:
如果我们在下半部分并且 v <u
要么
如果我们在上半部分并且(1-v)> u
然后我减一
现在,如果我很奇怪,我们仅需将j减1即可看到i是水平六边形索引(列),而j / 2的整数部分是垂直六边形索引(行)
规则的六边形具有六个对称轴,但是我将假设您的六边形只有两个对称轴(即,所有角度都不完全是60度)。不一定是因为您的不完全对称,而是因为它可能对其他人有用。
这是一个六边形的参数。其中心在O
,最大宽度在2a
,高度在2b
,上边缘的长度在2c
。
Y ^
|
____|____
/ b | |\
/ | | \
/ | | \
---(-------+---+---)------>
\ O| c / a X
\ | /
\____|____/
|
这是行/列的布局,其原点位于左下六角形的中心。如果您的设置不同,请平移(x,y)
坐标以退回这种情况,或者使用-y
代替y
例如:
col 0
| col 1
| | col 2
| | |
__ | __ __ __ __
/ \__/ \__/ \__/ \__/ \__
\__/ \__/ \__/ \__/ \__/ \
/ \__/ \__/ \__/ \__/ \__/
\__/ \__/ \__/ \__/ \__/ \
/ \__/ \__/ \__/ \__/ \__/_ _ line 2
\__/ \__/ \__/ \__/ \__/ \ _ _ _ line 1
/ .\__/ \__/ \__/ \__/ \__/_ _ line 0
\__/ \__/ \__/ \__/ \__/
下面的代码将为您提供包含点的六边形的行和列(x,y)
:
static void GetHex(float x, float y, out int row, out int column)
{
// Find out which major row and column we are on:
row = (int)(y / b);
column = (int)(x / (a + c));
// Compute the offset into these row and column:
float dy = y - (float)row * b;
float dx = x - (float)column * (a + c);
// Are we on the left of the hexagon edge, or on the right?
if (((row ^ column) & 1) == 0)
dy = b - dy;
int right = dy * (a - c) < b * (dx - c) ? 1 : 0;
// Now we have all the information we need, just fine-tune row and column.
row += (column ^ row ^ right) & 1;
column += right;
}
您可以检查上面的代码在此IdeOne运行中是否绘制了完美的六边形。
我已经在Stack Overflow上回答了一个具有相同目标的类似问题,为了方便起见,我将其重新张贴在这里:(注意-所有代码都是用Java编写和测试的)
此图显示了六角形网格的左上角,并且覆盖了一个蓝色方形网格。很容易找到一个点在哪个正方形内,这也将大致得出一个六角形。六边形的白色部分显示正方形和六边形网格共享相同坐标的位置,而六边形的灰色部分则显示它们不共享坐标的位置。
现在,解决方案非常简单,只需找到一个点位于哪个盒子中,然后检查该点是否在两个三角形中,然后在必要时更正答案即可。
private final Hexagon getSelectedHexagon(int x, int y)
{
// Find the row and column of the box that the point falls in.
int row = (int) (y / gridHeight);
int column;
boolean rowIsOdd = row % 2 == 1;
// Is the row an odd number?
if (rowIsOdd)// Yes: Offset x to match the indent of the row
column = (int) ((x - halfWidth) / gridWidth);
else// No: Calculate normally
column = (int) (x / gridWidth);
在这一点上,我们有了点所在的框的行和列,接下来我们需要针对六边形的两个上边缘测试我们的点,以查看我们的点是否位于上面的六边形中的任意一个中:
// Work out the position of the point relative to the box it is in
double relY = y - (row * gridHeight);
double relX;
if (rowIsOdd)
relX = (x - (column * gridWidth)) - halfWidth;
else
relX = x - (column * gridWidth);
具有相对坐标使下一步变得更容易。
就像上图中一样,如果我们的点的y > mx + c,我们知道我们的点位于直线上方,在我们的情况下,该点位于当前行和列的上方和左侧的六边形。请注意,java中的坐标系的y从屏幕左上角的0开始,而不是数学上通常的左下角,因此,左边缘使用负梯度,右边缘使用正梯度。
// Work out if the point is above either of the hexagon's top edges
if (relY < (-m * relX) + c) // LEFT edge
{
row--;
if (!rowIsOdd)
column--;
}
else if (relY < (m * relX) - c) // RIGHT edge
{
row--;
if (rowIsOdd)
column++;
}
return hexagons[column][row];
}
上例中使用的变量的简要说明:
m是渐变,所以m = c / halfWidth
这是SebastianTroy的答复的附录。我将其留为评论,但我的声誉还不够。
如果要按此处所述实现轴坐标系:http : //www.redblobgames.com/grids/hexagons/
您可以对代码进行一些修改。
代替
// Is the row an odd number?
if (rowIsOdd)// Yes: Offset x to match the indent of the row
column = (int) ((x - halfWidth) / gridWidth);
else// No: Calculate normally
column = (int) (x / gridWidth);
用这个
float columnOffset = row * halfWidth;
column = (int)(x + columnOffset)/gridWidth; //switch + to - to align the grid the other way
这将使坐标(0,2)与(0,0)和(0,1)在同一对角线上,而不是直接在(0,0)下方。
如果所有六边形都是使用相同的比例和位置制成的,则可以对碰撞使用某种叠加资源,类似于:
然后,您所要做的就是将碰撞图像放置在六边形所在的位置,获取鼠标相对于左角的位置,并查看相对位置的像素是否不是白色(这意味着发生碰撞)。
代码(未经测试):
bool IsMouseTouchingHexagon(Vector2 mousePosition, Vector2 hexagonPosition,
Rectangle hexagonRectangle, Texture2D hexagonImage)
{
Vector2 mousePositionToTopLeft = mousePosition - hexagonPosition;
// We make sure that the mouse is over the hexagon's rectangle.
if (mousePositionToTopLeft.X >= 0 && mousePositionToTopLeft.X < hexagonRectangle.Width &&
mousePositionToTopLeft.Y >= 0 && mousePositionToTopLeft.Y < hexagonRectangle.Height)
{
// Where "PixelColorAt" returns the color of a pixel of an image at a certain position.
if (PixelColorAt(hexagonImage, mousePositionToTopLeft) == Color.White)
{
// If the color is not white, we are colliding with the hexagon
return true;
}
}
// if we get here, it means that we did not find a collision.
return false;
}
您显然可以事先(对整个六边形图像)执行矩形碰撞检查,以提高整个过程的性能。
这个概念很容易理解和实施,但是仅在六角形都相同的情况下才有效。如果您只有一组可能的六边形尺寸,这也可能会起作用,这意味着您将需要多个碰撞覆盖。
如果发现它是一个非常简单的解决方案,可以解决更完整,更可重用的问题(使用数学方法真正找到冲突),但是在我看来,绝对值得尝试。
在《Game Programming Gems 7》上有一篇名为《蜜蜂与游戏玩家:如何处理六角形瓷砖》的文章,这正是您所需要的。
不幸的是,我目前没有这本书的副本,否则我可以稍微描述一下。