this is the first in a series of articles where I will cover some technical problems and solutions that occurred to me during the development of my game Syzygy. The fact that these problems presented themselves in the first place depends on a long and articulated series of game design decision that will be taken for granted and will not be discussed in these posts.
But first of all, we must at least clarify what the game is about. Syzygy is a puzzle game centered around the possibility of changing the connectivity of a grid-based map from squares to triangles and hexagons at any moment. That's quite a mouthful, see the following gif for a visual clarification:
From this basic concept, it is possible to articulate many puzzles, mainly centered around how you and other types of creatures can (or cannot) move in such a peculiar environment. Given that, all visual elements should contribute to the changing shape of the world: the map as well as the characters' appearance and the background. In this first post, we will focus on how the map can transition smoothly from one shape to the other; leaving the other topics for next time.
To tackle this first point, we must introduce the concept of geometrical tessellation.
A tiling or tessellation is the covering of a plane using one or more geometric shapes with no overlaps and no gaps. From mere trial and error we can easily see that there are only three ways to tessellate a plane using a single regular polygon, that is, using triangles, squares or hexagons.
A square tiling is highly symmetric while the other two not so much, leading to a couple of different arrangements. To have a consistent transition (and consistent gameplay!) we have to establish which of the possible variants we want to use: in my case, the top-left triangle have its tip upwards and the first column of hexagons is lower that the second one.
Tessellation done by means of a single regular polygon is usually called a regular tiling. As a side note, cubes are the only regular solid able to tessellate the space, so a 3D version of Syzygy would make no sense whatsoever. Obviously, using more than one shape or even keeping just one shape but using various sizes of it creates a number of new tilings. Extending the search to all polygons, instead that forcing ourselves to use only regular ones, let us discover that there is an infinite amount of tilings and that's exactly what we want for our transition animation.
To be more precise, we actually need three animations: one for every pair of shapes. The basic concept of all three animations is to linearly interpolate (lerp) between the vertices of the two extreme shapes to obtain a new shape, that is also a tessellation for every step of the lerp. I designed the transformation so that the area of a shape is constant across changes: it is not mathematically required to do so (e.g. it is possible to lerp from small triangles towards big squares), but it felt better this way since the whole grid remains approximately of the same size.
Let's see how to make it work case by case.
Triangles to Squares
In this transition, the tip of the triangle is split in two and the four vertices so obtained are lerped towards the positions they have in a square. As the shapes change, their center positions need to change too: luckily, this can also be taken care of with a simple lerp from the centroid of the triangle towards the centroid of the square.
Squares to Hexagons
This transition is fairly similar to the previous one: two vertices are added at the top or at the bottom of the square, depending on which column the shape lies on, and then the vertices are simply lerped into place. Notice that in both this animation and the previous one I am using only one shape that gets appropriately rotated, depending on the position it occupies on the grid.
Hexagons to Triangles
This is a little trickier. I have not bothered trying to prove it as a theorem, but I am pretty sure that it does not exist a way to lerp from hexagons to triangles using a single polygon, since the obtained one is not a tessellation. This is not really a problem though: it was neat as long as it lasted but I was never really against having more than one shape during the intermediate tessellations. In this case, two shapes are sufficient: they must be interlaced on alternate rows. As I stated earlier, the number of vertices per shape is bound to change during every transition but, since my biggest concern is having a consistent framerate, I always draw six vertices for every shape even when triangles are selected; some vertices will be overlapped, but it's ok.
And with this last remark, we have concluded the taxonomy of shape transitions. Any single one of them lasts 300 milliseconds in game, so they are barely visible. But, since the player is going to change shape all the time, I think it was worthwhile to make them as smooth as possible.
Thank you for keeping up till the end and I hope it has been an interesting and insightful reading. Stay tuned for the next part, in which we'll talk about how sprites are rendered and animated.