Recognizing a hexagonal clickbox

I'm working on a game that is going to involve gasp hexagons.

At present, I have a hexagon image that I am using (all sides are the same length...it fits into a 50px by 50px image).

I am somewhat new to C# and really new to XNA, but is there some sort of easy method that I can call rather than doing a convoluted if statement based on points and angles?

-
See gamedev.stackexchange.com/questions/6382/… which implements hex click detection. – Tim Holt Jul 22 '11 at 17:19
I totally Googled "gasp hexagons" I was like, "what kind of hexagon is that?!" Guess I'm having a slow day. – Byte56 Jul 22 '11 at 18:36
Hmm what happens if you click in the gasp rather than in the hexagon? – Tim Holt Jul 22 '11 at 18:44
Depending on your needs, a simple circle would do if its just for a click area. Otherwise you are going to have to use a point on polygon technique like winding sum or sumsuch. – PhilCK Jul 22 '11 at 19:15
Unless the hex map is to be arbitrarily rotated, point on polygon is MAJOR overkill. What do you do with a map that's 1000x1000 hexes? Check every one? RE: Circles, they will not work. Near the junction vertex between three hexes, you'll have three circles overlapping. Smaller circles that lie completely within the hexes will have gaps where legit clicks will not be in any circle. – Tim Holt Jul 22 '11 at 20:48

A hexagon is a rectangle with clipped corners. The way I've seen this done, and I've heard the Civilization series does it this way with orthogonal maps, is to create a bitmap with a white space (orthogonal or hexagonal), and a red, green, blue, and yellow corner. (Or whatever colors you like.)

Hexagonal: or

Orthogonal:

Then, just determine which rectangle the cursor is over, and test the color of the pixel at that location. If it's white, they're hovering over that space. Each other color is mapped to an offset, and they're hovering over that hexagon instead. This way is efficient, takes little geometry, and can be used for any arbitrarily tessellating space.

-
Just a note: A hexagon has 6 equal length sides. None of the images you presented actually contain hexagons. Instead, they contain 6 sided polygons. Other than that, this method works. It is likely slower than computing the bounds of the hexagon, for larger hexagons though, as this method requires more space for larger hexagons (if you want to keep per pixel accuracy). For small hexagons (and depending on the hardware), this method is probably faster than computing the bounds. – Olhovsky Jul 22 '11 at 14:20
A hexagon is any 6 sided polygon. What you are thinking of is an equilateral hexagon (actually, you're probably thinking of a regular hexagon, which is a type of equilateral and equiangular hexagon) – Random832 Jul 22 '11 at 16:58
Please note that I wasn't saying that your answer was bad. I think it's a good answer and a solution that has it's place. That said, I wouldn't choose this method over computing the hexagon bounds, as computing the hexagon bounds on any modern platform, as computing the bounds is a much more extensible way to do it. E.g. lets say you want to change the hexagon size -- now you have to rebuild the image? Producing a pixel perfect hexagon mask is a pain. The fact that you haven't produced one here is a testament to that, I think. – Olhovsky Jul 22 '11 at 18:17
@Olhovsky - I haven't produced a perfect hexagon mask here because I'm answering questions as a community service during my few minute breaks while at work, and not actually writing a video game. The OP was looking for a solution with less math, and I thought this was neat so I thought I'd share, because it's something I certainly wouldn't have thought of on my own. – dlras2 Jul 22 '11 at 18:27

Here i got a method that can be used to detect clicks inside any polygon:

``````public bool PointInPolygon( Vector2 p, Vector2[] poly )
{
Vector2 p1, p2;
bool inside = false;

if( poly.Length < 3 )
{
return inside;
}

Vector2 oldPoint = new Vector2( poly[poly.Length - 1].X, poly[poly.Length - 1].Y );

for( int i = 0; i < poly.Length; i++ )
{
Vector2 newPoint = new Vector2( poly[i].X, poly[i].Y );

if( newPoint.X > oldPoint.X )
{
p1 = oldPoint;
p2 = newPoint;
}
else
{
p1 = newPoint;
p2 = oldPoint;
}

if( ( newPoint.X < p.X ) == ( p.X <= oldPoint.X )
&& ( (long)p.Y - (long)p1.Y ) * (long)( p2.X - p1.X )
< ( (long)p2.Y - (long)p1.Y ) * (long)( p.X - p1.X ) )
{
inside = !inside;
}

oldPoint = newPoint;
}

return inside;
}
``````

You need to give the corners of your hexagon in a vector2 array (poly) and the clicked position (p) to the method.

-

There's no XNA method that does a hexagon hit test.

This article explains how to write a function that does the test, and gives you the function:

How to Check if a Point is Inside a Hexagon

Here is a summary from that article:

And the function that does the test goes like this:

1. Test the bounding box around the hexagon, early out if it does not intersect it.
2. Transform the point into a local quadrant as shown above.
3. Perform the following `isInside` test for the local quadrant.

``````public function isInside(pos:Vec2Const):Boolean
{
const q2x:Number = Math.abs(pos.x - _center.x);
const q2y:Number = Math.abs(pos.y - _center.y);
if (q2x > _hori || q2y > _vert*2)
return false;
return 2 * _vert * _hori - _vert * q2x - _hori * q2y >= 0;
}
``````

See the article for full details.

Here are some other useful related sources:

-