Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a hexagon tiled map in which i need to check when a hexagon is clicked. The hexagons aren't actually touching, rather they have a slight gap in between each of them.

Does anyone know how I could go about checking whether a hexagon is clicked without over complicating the whole thing?

share|improve this question

6 Answers 6

up vote 11 down vote accepted

Take a look to this picture

hexagonal decomposition

As you can see there is a relatively intuitive way to map x,y rectangular coordinate system to the hexagonal one.

We may talk about "rect" irregular hexagons ie hexagons inscribed in ellipses or hexagons obtained from regular hexagons scaled in both directions disproportionately (no rotations-shearings).

A rect hexagon can be defined by the height and width of the circumscribing rectangle plus the width of the inscribing one. (W,w,h)

inscribing/circumscribing rectangles

The easiest way to find out the hexagonal index is to partitionate the space as follow:

space partition

The rectangle width is w + (W - w)/2 = (w + W)/2, its height is h/2; the width of the green rectangle is (W-w)/2. Is easy to find out where in which rectangle the point falls:

enter image description here

u and v are the reminder coordinates that indicates where the point is whithin the i,j rectangle: Using w we can say if we are in the green area (u < (W-w)/2) or not.

if it is the case we are in the green area we need to know if we are in the upper or lower half of the hexagon: we are in the upper half if i and j are both even or both odd; we are in the lower half otherwise.

In both cases it is usefull to trasform u and v so they vary between 0 and 1:

enter image description here

if we are in the lower half and v < u

or

if we are in the upper half and (1-v) > u

then we decrement i by one

Now we simply have to decrement j by one if i is odd to see that i is the horizontal hexagon index (column) and the integer part of j/2 is the vertical hexagon index (row)

enter image description here

share|improve this answer
    
Thanks! Really helpful, had a few troubles arising with the splitting of the green section (should i subtract 1 from i or not), but i think that was due to the orientation of my hexagons. All working, thanks! –  Randomman159 Dec 10 '11 at 9:16

Regular hexagons have six axes of symmetry, but I will assume your hexagons only have two axes of symmetry (ie. all angles are not exactly 60-degrees). Not necessarily because yours don't have the full symmetry, but because it may be useful to someone else.

Here are the parameters of one hexagon. Its centre is in O, the largest width is 2a, the height is 2b, and the length of the top edge is 2c.

         Y ^
           |
       ____|____
      /  b |   |\
     /     |   | \
    /      |   |  \
---(-------+---+---)------>
    \     O|   c  / a      X
     \     |     /
      \____|____/
           |

This is the row/column layout, with the origin at the centre of the lower left hexagon. If your setup is different, translate your (x,y) coordinates to fall back on this case, or use -y instead of y for instance:

col 0
 | col 1
 |   | col 2
 |   |  |
 __  | __    __    __    __   
/  \__/  \__/  \__/  \__/  \__
\__/  \__/  \__/  \__/  \__/  \
/  \__/  \__/  \__/  \__/  \__/
\__/  \__/  \__/  \__/  \__/  \
/  \__/  \__/  \__/  \__/  \__/_ _ line 2
\__/  \__/  \__/  \__/  \__/  \ _ _ _ line 1
/ .\__/  \__/  \__/  \__/  \__/_ _ line 0
\__/  \__/  \__/  \__/  \__/

The following code will then give you the row and column of the hexagon containing point (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;
}

You can check that the above code draws perfect hexagons on this IdeOne run.

share|improve this answer
    
First time I've heard about ideOne, but it seems really useful! –  David Gouveia Dec 8 '11 at 14:52
    
@davidluzgouveia: yes, it is awesome. I am not fond of web or cloud services but this one is helpful. –  Sam Hocevar Dec 8 '11 at 15:06

You could fit 3 rotated rectangles inside the area of the hexagon, and if done properly it would fill the area exactly. Then it would be simply a matter of checking for collision on the three rectangles.

share|improve this answer

You probably don't need to de-register clicks between the tiles. That is to say, it won't hurt and might even help the player if you allow the spaces between tiles to be click-able as well unless you are talking about a large space between them that is filled with something that logically shouldn't be clicked. (Say, the hexes are cities on a large map where in-between them are other click-able things like people)

To do the above, you can simply plot the centers of all the hexes, and then find the nearest one to the mouse when clicked on the plane of all the hexes. The nearest center on a plane of tessellated hexagons will always be the same one you are hovering over.

share|improve this answer

If all your hexagons are made using the same proportions and placing, you could use some sort of overlay asset for the collisions, something along the lines of: The collision overlay for an hexagon

Then, all you have to do is place the collision image where your hexagon is, get the mouse position relative to the left corner, and see if the pixel of the relative position is NOT white (which means there is a collision).

Code (not tested):

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;
}

You could obviously perform a rectangle collision check beforehand (of your whole hexagon image) to improve performance of the whole process.

The concept is quite simple to understand and implement, but only works if your hexagons are all the same. It could also work if you only have a set of possible hexagon dimensions, which would then mean that you would need more than one collision overlay.

If find it to be a very simplistic solution to what could be a lot more complete and reusable (using maths to really find the collision) but it's definitely worth a try in my opinion.

share|improve this answer

There's an article on Game Programming Gems 7 called For Bees and Gamers: How to Handle Hexagonal Tiles which would be exactly what you need.

Unfortunately I don't have my copy of the book with me at the moment, otherwise I could have described it a little.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.