Hexagonal grid game




















In the diagram, each range is a pair of lines. Each line is an inequality a half-plane [26]. We pick all the hexes that satisfy all six inequalities. This loop also works nicely with axial coordinates:.

If you need to find hexes that are in more than one range, you can intersect the ranges before generating a list of hexes. You can either think of this problem algebraically or geometrically. I'm going to solve it algebraically:. We'll do the same for r and s , and end up with this generalization of the code from the previous section:.

Since a hex region is expressed as ranges over q, r, s, we can separately intersect each of the q, r, s ranges then use the nested loop to generate a list of hexes in the intersection. The same pattern works for intersecting three or more regions, and can generalize to other shapes [28] triangles, trapezoids, rhombuses, non-regular hexagons. If there are obstacles, the simplest thing to do is a distance-limited flood fill breadth first search.

In this diagram, the limit is set to moves. In the code, fringes[k] is an array of all hexes that can be reached in k steps.

Each time through the main loop, we expand level k-1 into level k. This works equally well with any of the hex coordinate systems cube, axial, offset, doubled. Given a hex vector difference between one hex and another , we might want to rotate it to point to a different hex. Take a look at the axis legend on the bottom left to see how this works. Here's the full recipe for rotating a position hex around a center position center to result in a new position rotated :.

It's several conversion steps but each step is short. You can shortcut some of these steps by defining rotation directly on axial coordinates, but hex vectors don't work for offset coordinates and I don't know a shortcut for offset coordinates. Also see this stackexchange discussion [29] for other ways to calculate rotation.

Given a hex, we might want to reflect it across one of the axes. With cube coordinates, we swap the coordinates that aren't the axis we're reflecting over. The axis we're reflecting over stays the same. To reach the other two reflections, negate the coordinates of the original and the first reflection.

These are shown as white arrows in the diagram. To reflect over a line that's not at 0, pick a reference point on that line.

Subtract the reference point, perform the reflection, then add the reference point back. To find out whether a given hex is on a ring of a given radius , calculate the distance from that hex to the center and see if it's radius. To get a list of all such hexes, take radius steps away from the center, then follow the rotated vectors in a path around the ring. In this code, hex starts out on the ring, shown by the large arrow from the center to the corner in the diagram.

I chose corner 4 to start with because it lines up the way my direction numbers work but you may need a different starting corner. At each step of the inner loop, hex moves one hex along the ring. The scale, add, and neighbor operations also work on axial and doubled coordinates, so the same algorithm can be used. For offset coordinates, convert to one of the other formats, generate the ring, and convert back.

Spirals also give us a way to count how many hexagon tiles are in the larger hexagon. The center is 1 hex. Given a location and a distance, what is visible from that location, not blocked by obstacles? The simplest way to do this is to draw a line to every hex that's in range. If the line doesn't hit any walls, then you can see the hex.

Mouse over a hex to see the line being drawn to that hex, and which walls it hits. This algorithm can be slow for large areas but it's so easy to implement that it's what I recommend starting with. There are many different ways to define what's "visible". Do you want to be able to see the center of the other hex from the center of the starting hex?

Do you want to see any part of the other hex from the center of the starting point? Maybe any part of the other hex from any part of the starting point? Are there obstacles that occupy less than a complete hex? Field of view turns out to be trickier and more varied than it might seem at first. Start with the simplest algorithm, but expect that it may not compute exactly the answer you want for your project.

There are even situations where the simple algorithm produces results that are illogical. Also see the Duelo [32] project, which has an an online demo of directional field of view [33] and code on Github.

Also see my article on 2d visibility calculation for an algorithm that works on polygons, including hexagons. For grids, the roguelike community has a nice set of algorithms for square grids see this [34] and this [35] and this [36] ; some of them might be adapted for hex grids.

For hex to pixel, it's useful to review the size and spacing diagram at the top of the page. For axial coordinates, the way to think about hex to pixel conversion is to look at the basis vectors. For example, the hex at 1,1 is the sum of 1 q vector and 1 r vector. A hex at 3,2 would be the sum of 3 q vectors and 2 r vectors. The code for flat top or pointy top is:. This can also be viewed as a matrix multiply, where the basis vectors are the columns of the matrix:.

The matrix approach will come in handy later when we want to convert pixel coordinates back to hex coordinates. Also, CSS grid requires us to have pretty flat markup, as all of our grid items have to be siblings right now.

Sub-grid will make this not a requirement, but it's not quite there yet and this proved to not be an issue anyway. As you can see, we have a pretty standard list going here. If you're curious about forcing ratios in CSS, this is a good article to check out. Alright, let's get into how this crazy grid system works. My first stab at this explored trying to figure out an auto placement scheme, but that quickly became a dead end as I realized that one of my requirements, interconnecting hexagons, was going to prevent any sort of automatic placement, at least from my understanding of grid.

CSS grids are super interesting in that they really don't care if there's an element already occupying the space that you tell them to go to, so if you tell multiple elements to occupy the same grid cell they will happily do that, but you have to explicitly tell the grid what elements you need to overlap, so auto placement was a no-go.

Once I figured that out, I moved into figuring out what my grid needed to actually look like. This proved to be far more challenging than I expected. Or maybe I'm just bad at math. I think that might be it. Well first, we need to turn our list into a grid. Figuring out what my rows needed to look like was actually pretty easy. If you look at the hexagon shape, you'll see that the top and the bottom are flat:. This, coupled with the fact that the hexagon is mirrored across the y-axis, means that we don't have to do anything special to set up our rows; all of that will automatically be taken care of when we start placing individual items into the correct spaces.

Columns were substantially harder to figure out. Looking at the the hexagon again, my initial thought was that I should be able to get away with a grid where each individual item spans 3 columns. The center is one column, and each side will occupy a column as well:.

Conveniently, the sides of the hexagon are exactly half the width of the center, meaning our grid columns should look something like 1 2 1 when we go to set up our columns for this grid. Similar to where the nodes run into the wall below. If you're running into performance issues at only 10 nodes out, you'll want to look at how you're accessing the nodes.

A breadth first search should be able to navigate hundreds of nodes without a noticeable delay certainly not a few seconds. Consider storing a simple version of your world in a graph format, for quick traversal. Amit Patel has provided an excellent resource for getting ranges on his site. In the article, he uses the following algorithm for collecting hex tiles within a range:.

This will find all the hexes within a certain distance of the center hex, if you want to consider obstacles, use the breadth first search from my other answer. Sign up to join this community. The best answers are voted up and rise to the top. Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams?

Learn more. Showing range on hexagonal grid Ask Question. Asked 9 years, 1 month ago. Active 2 years, 3 months ago.

The orientation will affect how the vertices are calculated. The vertices are numbered somewhat arbitrarily on my part, but we need to refer to vertices in some manner.

The important method in Hex is CalculateVertices , which is private and called by the constructor. I also created an enumeration for hexagonal orientation. The Hex class was designed to be simple.

All it does is remember its position in two dimensional space. The Board class is a collection of Hex objects that represent a game board. For this first version, the only type of board that can be created is rectangular. Arranging hexagons in a rectangular shape can be done fairly simply using a two dimensional array. For example, a board with Flat orientation would map to a two dimensional array like this:. The most important method in the Board class is Initialize , which is private and called from the constructor.

Initialize creates a two dimensional array of Hex objects with all the calculations for the hex vertices. This method starts by creating a Hex at the array position 0,0. After a Hex object is created, every other Hex can be created because some vertex of a Hex is also the vertex of another Hex. So, you can loop through the two dimensional array from top to bottom, left to right, creating Hex es.

The orientation will affect the calculations. I also created enumerations to give friendly names to the vertices. Draw then writes the Board and Hex es to a bitmap variable, and finally displays that bitmap to the screen. In this case, the state information is color. These classes are not strictly necessary, but I wanted to keep the Hex and Board classes as pure as possible, meaning that they only contain information about geometry and pixels.

This way, the stateful information is separated, and can be developed independently. To make this all work, you need to create a Form with a GraphicsEngine object and a Board object. This can be done in code or in the designer.



0コメント

  • 1000 / 1000