Generating a Hexagonal Grid in Processing

hexagon grid with 16 radius and walls

Learn how to generate a hexagonal grid, create walls, connect the hexagonal cells and render the cells in this Processing tutorial, using the Java programming language.

Open Processing

Open Processing, then create two variables which will represent the number of hexagonal grid cells as columns and rows.

final int columns = 12;
final int rows = 42;

Next create a list of nodes. We will create the “Node” class later.

final ArrayList<Node> nodeList = new ArrayList<Node>(columns*rows);

Add a variable for the radius of a hexagon cell.

final float hexagonRadius = 16;

Node

Create a new tab called “Node”. Then create a new class called “Node”.

class Node
{
  PVector position = new PVector();
  ArrayList<Node> adjacentNodes = new ArrayList<Node>();
  boolean isWall = false;
}

The node class has a position, a list of adjacent nodes and a boolean to determine if it is a wall or not.

Create a new function for creating a node, and setting it’s position.

void CreateNode(float x, float y)
{
  Node node = new Node();
  node.position.set(x, y);
  nodeList.add(node);
}

Create Hexagon Grid

Next create a new function, which will be used to create a grid of hexagons. The hexagons will have flat tops, and will be rendered from their own centre.

void CreateHexagonGrid(float columns, float rows, float radius)
{
}

Inside the new function create some variables, which will represent the size of the hexagon.

  final float hexagonWidth = 2.0f * radius;
  final float hexagonHeight = sqrt(3) * radius;
  
  final float quarterWidth = hexagonWidth / 4.0f;
  final float quarterHeight = hexagonHeight / 4.0f;

Next we will calculate the start point, which will be the centre of the window. We need to use the size of the hexagon and the spacing between the hexagons to figure out the size of the grid.

  final PVector startPoint = new PVector(0, 0);
  startPoint.add(hexagonWidth * 0.375f, hexagonHeight / 2);
  startPoint.add(width / 2, height / 2);
  startPoint.sub(quarterWidth * columns * 3, (4 + 2 * (rows - 1)) / 2 * quarterHeight);

Now we need some more variables to figure out the placement of the hexagons.

  final float h = hexagonWidth + radius;
  final float v = hexagonHeight / 2.0f;
  final float offsetX = (3.0f / 2.0f) * radius;
  float ox = 0;

Then we can create the hexagons inside a double for loop. We will only apply the offset when the row value is an even number.

  for(int y=0; y<rows; ++y)
  {
    for(int x=0; x<columns; ++x)
    {
      ox = y % 2 == 0 ? offsetX : 0;
      CreateNode(startPoint.x + h * x + ox, startPoint.y + v * y);
    }
  }

For more information on the spacing and size of hexagonal grids, check out this post.

Create Walls

Next create a new function which will create the walls. The function will randomly turn grid cells into walls using a random seed value. The seed value can be adjusted to create different map layouts. Feel free to play around with it.

void CreateWalls()
{
  randomSeed(3);
  final int gridTotal = columns*rows-1;
  final int loopTotal = gridTotal / 2;
  for(int i=0; i<loopTotal; ++i)
  {
    nodeList.get((int)random(0, gridTotal)).isWall = true;
  }
}

Connect Nodes

Now we will create a new function which will connect the nodes. Nodes will only be connected if they are close to each other and if they are not a wall. It is more efficient to use the squared version of a number, rather than a square root when measuring distances.

void ConnectNodes(float radius)
{
  final float squaredRadius = radius * radius * 4;
  float magSquared = 0;
  final PVector delta = new PVector();
  for(Node a : nodeList)
  {
    if(a.isWall) continue;
    for(Node b : nodeList)
    {
      if(a == b || b.isWall) continue;
      delta.set(a.position);
      delta.sub(b.position);
      magSquared = delta.magSq();
      if (magSquared < squaredRadius)
      {
        a.adjacentNodes.add(b);
      }
    }
  }
}

Setup

Next we will create a “setup” function. We set the window size, then create the hexagons, then the walls, then finally connect the nodes.

void setup()
{
  size(720, 720);
  CreateHexagonGrid(columns, rows, hexagonRadius);
  CreateWalls();
  ConnectNodes(hexagonRadius);
}

Render Polygon

Now we can write the render functions. First we need a function for rendering a regular polygon, since a hexagon is a type of polygon. Luckily Processing has written one for us, so we will reuse it.

void RenderPolygon(float x, float y, float radius, int npoints)
{
  float angle = TWO_PI / npoints;
  beginShape();
  for (float a = 0; a < TWO_PI; a += angle) {
    float sx = x + cos(a) * radius;
    float sy = y + sin(a) * radius;
    vertex(sx, sy);
  }
  endShape(CLOSE);
}

Next we will create a convenience function for rendering a hexagon.

void RenderHexagon(PVector position, float radius)
{
  RenderPolygon(position.x, position.y, radius, 6);
}

Render Hexagon Grid

Now we will render our hexagon grid by looping through every node and rendering a hexagon at the node’s position. Note that we change the fill colour of walls, so they look different to the regular hexagon cells.

void RenderHexagonGrid()
{
  strokeWeight(3);
  stroke(150);
  for(Node node : nodeList)
  {
    if(node.isWall)
    {
      fill(100);
    }
    else
    {
      fill(220);
    }
    RenderHexagon(node.position, hexagonRadius);
  }
}

Draw

Next we will create the “draw” function. Which will clear the screen to a dark grey colour, then draw the grid of hexagons.

void draw()
{
  background(50);
  RenderHexagonGrid();
}

Finally you just need to run the sketch, and you should see a nice grid of hexagons!

Conclusion

Thanks for reading this tutorial. You have learned how to generate a hexagonal grid, create walls, connect the hexagonal cells and render the cells.

Check out the next tutorial, which shows you how to explore the hexagon grid using the greedy best first search algorithm.

hexagon grid with 32 radius and walls
Hexagon grid with 32 radius and walls

2 responses to “Generating a Hexagonal Grid in Processing”

Leave a reply to pk 🌎 Cancel reply