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.

My 2D isometric game uses a hexagonal grid map. In reference to the image below, how do I rotate the light blue hexagon structures by 60 degrees around the pink hexagons?

http://www.algonet.se/~afb/spriteworld/ongoing/HexMap.jpg

EDIT:

Main hex is (0,0). Other hexes are childs, count of them is fixed. I'm going to define only one position (in this case its right) and other directions calculate if needed (left-bottom, right-botom, right-top, left-top and left). Other hexes are defined like: Package.Add(-1,0), Package.Add(-2,0) and so on. enter image description here

switch(Direction)
{
case DirRightDown:
    if(Number.Y % 2 && Point.X % 2)
        Number.X += 1;
    Number.Y += Point.X + Point.Y / 2;

    Number.X += Point.X / 2 - Point.Y / 1.5;
    break;
}

In this code 'Number' is Main Hex and Point is hex that i want to rotate. But i doesnt work:

enter image description here

share|improve this question
1  
what exactly is the problem? how to implement that or some bad results? –  Ali.S Jul 26 '11 at 19:19
    
Are you snapping rotations to the 6 edges of the pink hexagon, or are the rotation angles arbitrary? Also, which of the pink hexagons in the right-side structure are you rotating around? –  Keeblebrox Jul 26 '11 at 20:45
    
It may just be easier to rotate the individual tiles but this leads to the question of what happens to the tiles that are already there and this would be good to know in general before I can try and give a response. –  James Jul 26 '11 at 21:02
    
Sorry for mistake. I'm talking about left part of the image. I had bad results, ever some hexes are in wrong places. The pink hex is main and bright blue hexes are childs. Suppose main hex is (5,5) then i define a child hex (-1,0) so the child is on the left side of pink and so on. I wanna to know how rotate this child hex by 60 degrees (then it will been at left-top of pink). easier: i'm working on build system in my strategy game. Often in strategy games you can rotate building before you place it. I'm going to calculate the hexes that need to build. –  ruzsoo Jul 26 '11 at 21:34
    
Does the set of selected hexes have to be exactly the same count every time? That is, are you for example specifically placing 3 objects on the hexes on either side of the pink hex? Or are you just wanting to draw a line of a given length and decide which hexes best intersect it, irrespective of how many that will be? Are you wanting to do this with a fixed number of hexes, or an arbitrary number? –  Tim Holt Jul 26 '11 at 21:58

2 Answers 2

Let's first define a new number. No worries, it's an easy one.

  • f: f × f = -3

Or, to put it simply: f = √3 × i, with i being the imaginary unit. With this, a rotation by 60 degrees clockwise is the same as multiplication by 1/2 × (1 - f), and rotation by 60 degrees counter-clockwise the same as multiplication by 1/2 × (1 + f). If this sounds strange, remember that multiplication by a complex number is the same as rotation in the 2D plane. We just "squash" the complex numbers in the imaginary direction a bit (by √3) to not have to deal with square roots ... or non-integers, for that matter.

We can also write the point (a,b) as a + b × f.

This lets us rotate any point in the plane; for example, the point (2,0) = 2 + 0 × f rotates to (1,-1), then to (-1,-1), (-2,0), (-1,1), (1,1) and finally back to (2,0), simply by multiplying it.

Of course, we need a way to translate those points from our coordinates to those we do the rotations in, and then back again. For this, another bit of information is needed: If the point we do the rotation around is to the "left" or to the "right" of the vertical line. For simplicity, we declare that is has a "wobble" value w of 0 if it's to the left of it (like the center of the rotation [0,0] in your bottom two pictures), and of 1 if it's to the right of it. This extends our original points to be three-dimensional; (x, y, w), with "w" being either 0 or 1 after normalisation. The normalisation function is:

NORM: (x, y, w) -> (x + floor(w / 2), y, w mod 2), with the "mod" operation defined such that it only returns positive values or zero.

Our algorithm now looks as follows:

  1. Transform our points (a, b, c) to their positions relative to the rotational centre (x, y, w) by calculating (a - x, b - y, c - w), then normalising the result. This puts the rotational centre at (0,0,0) obviously.

  2. Transform our points from their "native" coordinates to the rotational complex ones: (a, b, c) -> (2 × a + c, b) = 2 × a + c + b × f

  3. Rotate our points by multiplying them with one of the rotational numbers above, as needed.

  4. Ra-transform the points back from the rotational coordinates to their "native" ones: (r, s) -> (floor(r / 2), s, r mod 2), with "mod" defined as above.

  5. Re-transform the points back to their original position by adding them to the rotational centre (x, y, z) and normalising.


A simple version of our "triplex" numbers based f in C++ would look like this:

class hex {
    public:
        int x;
        int y;
        int w; /* "wobble"; for any given map, y+w is either odd or
                  even for ALL hexes of that map */
    hex(int x, int y, int w) : x(x), y(y), w(w) {}
    /* rest of the implementation */
};

class triplex {
    public:
        int r; /* real part */
        int s; /* f-imaginary part */
        triplex(int new_r, int new_s) : r(new_r), s(new_s) {}
        triplex(const hex &hexfield)
        {
            r = hexfield.x * 2 + hexfield.w;
            s = hexfield.y;
        }
        triplex(const triplex &other)
        {
            this->r = other.r; this->s = other.s;
        }
    private:
        /* C++ has crazy integer division and mod semantics. */
        int _div(int a, unsigned int b)
        {
            int res = a / b;
            if( a < 0 && a % b != 0 ) { res -= 1; }
            return res;
        }
        int _mod(int a, unsigned int b)
        {
            int res = a % b;
            if( res < 0 ) { res += a; }
            return res;
        }
    public:
        /*
         * Self-assignment operator; simple enough
         */
        triplex & operator=(const triplex &rhs)
        {
            this->r = rhs.r; this->s = rhs.s;
            return *this;
        }
        /*
         * Multiplication operators - our main workhorse
         * Watch out for overflows
         */
        triplex & operator*=(const triplex &rhs)
        {
            /*
             * (this->r + this->s * f) * (rhs.r + rhs.s * f)
             * = this->r * rhs.r + (this->r * rhs.s + this->s * rhs.r ) * f
             *   + this->s * rhs.s * f * f
             *
             * ... remembering that f * f = -3 ...
             *
             * = (this->r * rhs.r - 3 * this->s * rhs.s)
             *   + (this->r * rhs.s + this->s * rhs.r) * f
             */
            int new_r = this->r * rhs.r - 3 * this->s * rhs.s;
            int new_s = this->r * rhs.s + this->s * rhs.r;
            this->r = new_r; this->s = new_s;
            return *this;
        }
        const triplex operator*(const triplex &other)
        {
            return triplex(*this) *= other;
        }
        /*
         * Now for the rotations ...
         */
        triplex rotate60CW() /* rotate this by 60 degrees clockwise */
        {
            /*
             * The rotation is the same as multiplikation with (1,-1)
             * followed by halving all values (multiplication by (1/2, 0).
             * If the values come from transformation from a hex field,
             * they will always land back on the hex field; else
             * we might lose some information due to the last step.
             */
            (*this) *= triplex(1, -1);
            this->r /= 2;
            this->s /= 2;
        }
        triplex rotate60CCW() /* Same, counter-clockwise */
        {
            (*this) *= triplex(1, 1);
            this->r /= 2;
            this->s /= 2;
        }
        /*
         * Finally, we'd like to get a hex back (actually, I'd
         * typically create this as a constructor of the hex class)
         */
        operator hex()
        {
            return hex(_div(this->r, 2), this->s, _mod(this->r, 2));
        }
};
share|improve this answer

As Martin Sojka notes, rotations are simpler if you convert to a different coordinate system, perform the rotation, then convert back.

I use a different coordinate system than Martin does, labeled x,y,z. There's no wobble in this system, and it's useful for lots of hex algorithms. In this system you can rotate the hex around 0,0,0 by “rotating” the coordinates and flipping their signs: x,y,z turns into -y,-z,-x one way and -z,-x,-y the other way. I have a diagram on this page.

(I'm sorry about x/y/z vs X/Y but I use x/y/z on my site and you use X/Y in your code so in this answer the case matters! So I'm going to use xx,yy,zz as the variable names below to try to make it easier to distinguish.)

Convert your X,Y coordinates to the x,y,z format:

xx = X - (Y - Y&1) / 2
zz = Y
yy = -xx - zz

Perform a rotation by 60° one way or the other:

xx, yy, zz = -zz, -xx, -yy
     # OR
xx, yy, zz = -yy, -zz, -xx

Convert the x,y,z back to your X,Y:

X = xx + (zz - zz&1) / 2
Y = zz

For example, if you start with (X=-2, Y=1) and want to rotate 60° right, you'd convert:

xx = -2 - (1 - 1&1) / 2 = -2
zz = 1
yy = 2-1 = 1

then rotate -2,1,1 60° right with:

xx, yy, zz = -zz, -xx, -yy = -1, 2, -1

as you see here:

Hex rotation example for -2,1,1

then convert -1,2,-1 back:

X = -1 + (-1 - -1&1) / 2 = -2
Y = -1

So (X=-2, Y=1) rotates 60° right into (X=-2, Y=-1).

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.