How to generate list of hexagonal coordinates?
I got a hexagon-shaped model that I want to instantiate a number of times to create a circular hexagon grid - the function would input the number of rings wanted. I can't seem to figure out an algorithm that'll instantiate the hexagons in the right coordinates, however.
For simplicity's sake, I start out instantiating the middle hexagon at (0, 0, 0) in world space. It is rotated so it is flat on the left and right, and the next hexagon would be generated at (0, 0, 1), positioning it directly to the right of the middle one - then I'd wish to keep going in a circle until the specified amount of circles have been generated. The goal would be to have something like this generated if, for instance, the ring number is 5:
My function so far looks like this:
void BuildMap()
{
//Determines how many rings the map will have - 0 is a single tile)
int radius = 4;
//Empty list of coordinates
List<Vector3> tileCoordinates = new List<Vector3>();
//Code to fill the list with coordinates
//???
for (int i = 0; i < tileCoordinates.Count; i++)
{
//Create new tile and name it
GameObject newTile = (GameObject)Instantiate(tileSlot, tileCoordinates[i], Quaternion.identity);
newTile.gameObject.name = "tile_"+i.ToString();
}
}
I'm no expert at math though and the coordinate generation has me stumped... any advice here would be appreciated.
I think the key insight is probably to notice that the centres of the hexagons form a grid of equliateral triangles. Calculate L and H, the side length and height of those triangles respectively, and then the relative positions of the hexagons becomes straightforward. I would also be thinking in terms of rows of hexagons rather than rings.
Rough idea... You make a central row with (2n +1 hexagons) with an lateral distance of L between them, then above and below you add a row with one fewer hexagons, their centres displaced vertically by H and laterally by L/2 compared to the previous row. Stop when you've done the rows with (n+1) in them.
This is a nice and fairly straightforward approach - I'll try implementing this in practice and will share my results!
Answer by ivarhill · Jan 20, 2016 at 02:49 AM
Solved this issue with an implementation of Bonfire Boy's general idea:
//Empty list of coordinates
List<Vector3> tileCoordinates = new List<Vector3>();
//Code to fill the list with coordinates
//Adds the middle tile
tileCoordinates.Add(new Vector3(0, 0, 0));
//Generates the central row
for (int i = 0; i < radius; i++)
{
tileCoordinates.Add(new Vector3(0, 0, i+1));
tileCoordinates.Add(new Vector3(0, 0, -i-1));
}
//Generates remaining rows
int rowsRemaining = radius * 2; //Tracks amount of rows left to generate
float horizontalDisplacement = 0; //How far the generated tile should be moved horizontally
float verticalDisplacement = 0; //How far the generated tile should be moved vertically
int currentRowLength = radius * 2; //Length of the current row being generated (amount of tiles)
//This loops runs once for each row remaining
for (int rowID = 0; rowID < rowsRemaining; rowID++)
{
//If past half the rows (thus switching to lower rows), reset counters
if (rowID == radius)
{
horizontalDisplacement = 0;
verticalDisplacement = 0;
currentRowLength = radius * 2;
}
//For each row, update the counters
horizontalDisplacement = horizontalDisplacement + 0.5f;
currentRowLength = currentRowLength - 1;
//If it's an upper row
if (rowID < radius)
{
verticalDisplacement = verticalDisplacement + 0.866f;
}
//If it's a lower row
else
{
verticalDisplacement = verticalDisplacement - 0.866f;
}
//Generate the tile coordinates for this row
for (int tileID = 0; tileID <= currentRowLength; tileID++)
{
tileCoordinates.Add(new Vector3(verticalDisplacement, 0, radius - tileID - horizontalDisplacement));
}
}
//Use the generated list of coordinates to instantiate the tile prefabs
for (int i = 0; i < tileCoordinates.Count; i++)
{
//Create new tile and name it
GameObject newTile = (GameObject)Instantiate(tileSlot, tileCoordinates[i], Quaternion.identity);
newTile.gameObject.name = "tile_"+i.ToString();
}
This correctly generates a grid with the right shape with any radius specified.
Answer by cjdev · Jan 19, 2016 at 10:59 AM
Unfortunately I can't post images at the moment, but imagine a hexagon with the pointy end down as the outline of a cube in perspective, sitting on the X-Y-Z axis. Instead of thinking of the coordinate grid as (x,y) for horizontal and vertical, think of it as (x,y,z) for up, bottom right, and bottom left. This way instead of splitting the graph into quadrants, you've split it into thirds and the angles of that compliment the hexagons much better. In order to actually make a 'hexagonal circle' let's call it, which it actually will be in the new system I guess, you've got to iterate over all the coordinates that are within the 'radius' of the circle, which will just be the value you choose with this system. Then there's what could be the tricky matter of getting the conversion from x-y-z to x-y, I would personally try to map the coordinates directly or use them to find the angle from the center and translate it from there.