hexagon grid?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Q
Posts: 6
Joined: Thu Mar 09, 2006 2:23 pm

hexagon grid?

Post by Q »

I have a 2D grid of squares. When I click the mouse I can easily determine which square the mouse was in with some division

Now I want to move to a 2D hexagon grid and be able to tell which hexagon the mouse pointer is in? How would I do this? Is there a formula for calculating this?
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

You can follow this article for regular hexagons:
http://www.gamedev.net/reference/articl ... le1800.asp
I think it has a bug somewhere in the pseudocode, but cant remember where or what affected.

Or take a look at my own calculation for non-regular hexagons:
Image

that uses this code to get the work for a scrolling map:

Code: Select all


// ****************** //
//    pixel2tile      //
// ****************** //
// Calculate the tile where mouse pointer lays. This function should
// only be invoked if pointer is inside map area. Test for the area
// has to be made out of this function
// x, y are pixel coordinates (window, not map)
// Stores calculated coordinates in tileRow and tileCol pointers
void GRender::pixel2Tile(int initRow, int initCol, int x, int y, int* tileRow, int* tileCol) {
	
	int r = HEX_SIZE/4;	
	int wW = 6*r, wH = 8*r;

	int finalR, finalC; // Row and Col tile offsets inside aux window

	// Let other methods do the hard work
	x -= mapx;
	y -= mapy;
	if(initCol & 1) {
		window2Tile4Odd(&finalR, &finalC, x, y);
	} else {
		window2Tile4Even(&finalR, &finalC, x, y);
	}
	
	(*tileRow) = (y / wH)*2 + finalR + initRow;
	(*tileCol) = (x / wW)*2 + finalC + initCol;	
}


// ******************** //
//   window2Tile4Even   //
// ******************** //
// Explore auxiliar window intervals and store relative tile
// coordinates in finalR and finalC
// Zones in this method apply to maps starting with even column on index 0
// x, y are coordinates inside map (mapx -> mapw and mapy -> maph axis)
void GRender::window2Tile4Even(int* finalR, int* finalC, int x, int y) {
	
	// Useful vars
	int r = HEX_SIZE/4, so_3r = 3*r, so_2r = 2*r, so_4r = HEX_SIZE;
	int so_6r = 6*r, so_8r = HEX_SIZE*2;	
	
	int remX = x % (6*r), remY = y % (8*r); // Remainders inside window

	int p2tOffset = 4; // adjust pixel scale to easy integer geometry
	// Check X inside window interval
	if(remX<r) {				// x [ 0 -  r)
		
		remX = MAX(1, remX - p2tOffset);

		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			
			remY = so_2r-remY;
			
			if((remY/remX) > 2) {
				(*finalR) = -1;
				(*finalC) = -1; 

			} else {
				(*finalR) =  0;
				(*finalC) =  0;				
			}
			
		} else if(remY<so_4r) {		// y [2r - 4r)
			
			remY = so_2r-remY;			
			
			if((remY/remX) < -2) {
				(*finalR) =  0;
				(*finalC) = -1;

			} else {
				(*finalR) =  0;
				(*finalC) =  0;				
			}

		} else if(remY<so_6r) {		// y [4r - 6r)
			
			remY = so_6r-remY;			
			
			if((remY/remX) > 2) {
				(*finalR) =  0;
				(*finalC) = -1;

			} else {
				(*finalR) =  1;
				(*finalC) =  0;				
			}

		} else {					// y [6r - 8r)
			
			remY = so_6r-remY;			

			if((remY/remX) < -2) {
				(*finalR) =  1;
				(*finalC) = -1;

			} else {
				(*finalR) =  1;
				(*finalC) =  0;				
			}

		}
		
	
	} else if(remX<so_3r) {		// x [ r - 3r)
		
		// Y intervals
		if(remY<so_4r) {			// y [ 0 - 4r)
			(*finalR) =  0;
			(*finalC) =  0;
		
		} else {					// y [4r - 8r)
			(*finalR) =  1;
			(*finalC) =  0;
		}
	
	} else if(remX<so_4r) {		// x [3r - 4r)
	
		remX = MAX(1, remX - so_3r - p2tOffset);

		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			
			remY = 0-remY;
			
			if((remY/remX) < -2) {
				(*finalR) =  0;
				(*finalC) =  0; 

			} else {
				(*finalR) = -1;
				(*finalC) =  1;				
			}
			
		} else if(remY<so_4r) {		// y [2r - 4r)
			
			remY = so_4r-remY;			
			
			if((remY/remX) > 2) {
				(*finalR) =  0;
				(*finalC) =  0;

			} else {
				(*finalR) =  0;
				(*finalC) =  1;				
			}

		} else if(remY<so_6r) {		// y [4r - 6r)
			
			remY = so_4r-remY;			
			
			if((remY/remX) < -2) {
				(*finalR) =  1;
				(*finalC) =  0;

			} else {
				(*finalR) =  0;
				(*finalC) =  1;				
			}

		} else {					// y [6r - 8r)
			
			remY = so_8r-remY;			

			if((remY/remX) > 2) {
				(*finalR) =  1;
				(*finalC) =  0;

			} else {
				(*finalR) =  1;
				(*finalC) =  1;				
			}

		}		
	
	} else  {					// x [4r - 6r)
		
		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			(*finalR) = -1;
			(*finalC) =  1;
		
		} else if(remY<so_6r) {		// y [2r - 6r)
			(*finalR) =  0;
			(*finalC) =  1;
		
		} else {					// y [6r - 8r)
			(*finalR) =  1;
			(*finalC) =  1;
		}

	}
}


// ******************** //
//   window2Tile4Odd   //
// ******************** //
// Explore auxiliar window intervals and store relative tile
// coordinates in finalR and finalC
// Zones in this method apply to maps starting with odd column on index 0
// x, y are coordinates inside map (mapx -> mapw and mapy -> maph axis)
void GRender::window2Tile4Odd(int* finalR, int* finalC, int x, int y) {
	
	// Useful vars
	int r = HEX_SIZE/4, so_3r = 3*r, so_2r = 2*r, so_4r = HEX_SIZE;
	int so_6r = 6*r, so_8r = HEX_SIZE*2;	
	
	int remX = x % (6*r), remY = y % (8*r); // Remainders inside window

	int p2tOffset = 4; // adjust pixel scale to easy integer geometry
	// Check X inside window interval
	if(remX<r) {				// x [ 0 -  r)
	
		remX = MAX(1, remX - p2tOffset);

		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			
			remY = 0-remY;
	
			if((remY/remX) < -2) {
				(*finalR) =  0;
				(*finalC) = -1; 

			} else {
				(*finalR) = -1;
				(*finalC) =  0;				
			}
			
		} else if(remY<so_4r) {		// y [2r - 4r)
			
			remY = so_4r-remY;
			
			if((remY/remX) > 2) {
				(*finalR) =  0;
				(*finalC) = -1;

			} else {
				(*finalR) =  0;
				(*finalC) =  0;				
			}

		} else if(remY<so_6r) {		// y [4r - 6r)
			
			remY = so_4r-remY;			
			
			if((remY/remX) < -2) {
				(*finalR) =  1;
				(*finalC) = -1;

			} else {
				(*finalR) =  0;
				(*finalC) =  0;				
			}

		} else {					// y [6r - 8r)
			
			remY = so_8r-remY;			

			if((remY/remX) > 2) {
				(*finalR) =  1;
				(*finalC) = -1;

			} else {
				(*finalR) =  1;
				(*finalC) =  0;				
			}

		}
		
	
	} else if(remX<so_3r) {		// x [ r - 3r)
		
		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			(*finalR) = -1;
			(*finalC) =  0;
		
		} else if(remY<so_6r) {		// y [ 0 - 6r)
			(*finalR) =  0;
			(*finalC) =  0;
		
		} else {					// y [6r - 8r)
			(*finalR) =  1;
			(*finalC) =  0;
		}
	
	} else if(remX<so_4r) {		// x [3r - 4r)
	
		remX = MAX(1, remX - so_3r - p2tOffset);

		// Y intervals
		if(remY<so_2r) {			// y [ 0 - 2r)
			
			remY = so_2r-remY;
			
			if((remY/remX) > 2) {
				(*finalR) = -1;
				(*finalC) =  0; 

			} else {
				(*finalR) =  0;
				(*finalC) =  1;				
			}
			
		} else if(remY<so_4r) {		// y [2r - 4r)
			
			remY = so_2r-remY;
						
			if((remY/remX) < -2) {
				(*finalR) =  0;
				(*finalC) =  0;
			} else {
				(*finalR) =  0;
				(*finalC) =  1;
			}

		} else if(remY<so_6r) {		// y [4r - 6r)
			
			remY = so_6r-remY;
						
			if((remY/remX) > 2) {
				(*finalR) =  0;
				(*finalC) =  0;

			} else {
				(*finalR) =  1;
				(*finalC) =  1;				
			}

		} else {					// y [6r - 8r)
			
			remY = so_6r-remY;
			
			if((remY/remX) < -2) {
				(*finalR) =  1;
				(*finalC) =  0;

			} else {
				(*finalR) =  1;
				(*finalC) =  1;				
			}

		}		
	
	} else if(remX<so_6r) {		// x [4r - 6r)
		
		// Y intervals
		if(remY<so_4r) {			// y [ 0 - 4r)
			(*finalR) =  0;
			(*finalC) =  1;
		
		} else {					// y [4r - 8r)
			(*finalR) =  1;
			(*finalC) =  1;
		}

	}
}
Thats the game working with scroll:
Image

I could port it to Java, so it is also working for a totally scrollable map (this means it can scroll to any pixel, instead of scrolling by 1 cell step):
Image
LwSiX
Posts: 22
Joined: Wed Jan 17, 2007 2:24 pm

Post by LwSiX »

Yes i realize this post is almost a year old, but i have to know how you got the GUI like that in your first screen shot? Is that using the built in GUI functions?
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

First one is a modified image, not a real screenshot.
Second one is the game done with Allegro Library (not irrlicht)
Last one is done with Java Swing.
Warchief's Warboard 3D Now hotseat release
Post Reply