Introducing: Hex Tactics


Last month, I started up a 5-week side project creating a mech tactics game on a hex grid, creatively (/s) entitled Hex Tactics!

Hex Tactics game

My primary goal was for the project to serve as a rapid prototyping study. The basic game design and mechanics are inspired by existing games, so this would be predominantly an exercise in quickly building out features in the Unity game engine.

My projects in recent years had all been team-based, so this was also an opportunity to develop something solo again. This meant I could measure my gamedev skills more directly and stretch across a broader range of systems and disciplines than usual.

Finally, I knew that the core game design lent itself well to extension. This way, the project could allow exploring various areas of interest. In fact, the 5-week period wound up neatly dividing into a series of distinct phases:

  1.   Rapid Prototype    [14 Days]
  2.   AI Extension          [6 Days]
  3.   Polish Phase         [6  Days]
  4.   Procgen Iteration   [10 Days]

In this post, I'll describe the first phase in some detail, and in posts soon to follow, I'll cover the other development phases as well.


Solo Game Jam

Normally this time of year, I would have participated in the annual Seattle Indies Game Jam as I had done in the past. However, I wasn't sure how much time I could spare. Instead, I decided to work solo on a project in parallel with the 2020 jam. This allowed me to still have a deadline to work toward, while avoiding having a jam team relying on me, only to be pulled away by the day job. Fortunately, this project didn't suffer any major interruptions, and coincidentally, because I was not participating directly in jam, I was able to accept an invitation to serve as a judge for the jam's awards. I strongly recommend checking out the submissions this year, as many teams produced some truly impressive results!

Seattle Indies

Seattle Indies is a local organization fostering a community of game developers in the Puget Sound area. Among other events, they host a variety of game jams throughout the year, which I've often enjoyed participating in.


Getting Started

The more you do in gamedev, the greater a foundation you develop to jump-start new projects. A few years prior, I had written an open-source Hex Grids library for use in Unity. That had been largely produced in the abstract, and this project was actually my first opportunity using it in a playable game. The first few days were dedicated to integrating and adapting that library for the purposes of this project. While some adjustments were needed, I was pleased with how well it fit in. Very soon, the game had generation of a hex map, controls for selecting mechs, moving them on paths aligned to the grid, and accurately rotating them to face mechs on other tiles.

Pathfinding on a Hexagonal Grid

Amit Patel's Red Blob Games blog was an excellent source for research and inspiration at the time I originally wrote my C# hex library.


Core UI & Mechanics

The next few days involved implementing the functionality and UI for mech health and unit turns. I added a health bar over the mechs that updated with damage. Upon reaching zero health, the mech's death animation would play as it collapsed to the ground. Meanwhile, for the sake of simplicity, I implemented a basic turn order scheme, such that each individual unit would exercise their turn in the same order every round. The human player's units would go first, followed by that of the computer player, skipping over dead units. Each turn would consist of an optional move action followed by an attack action (attacking first would effectively skip the move action). I knew initially at least, all mechs would be essentially the same class and have the same actions. This approach helped reduce the project's scope by ignoring the nuances of evaluating unit initiative and/or handling dynamic turn orders.

Unit Turn UI


Introducing the AI

Around the halfway point (about 1 week in), I implemented the initial version of Artificial Intelligence (AI) for managing the enemy units. At this stage, I only needed the AI to keep the turns progressing and provide some challenge for the player. This iteration would become the "Easy" difficulty mode. The AI operates each unit independently and follows a straightforward decision tree. If an opponent is already in sight, the unit attacks it immediately. If not, the unit evaluates neighboring positions up to a few hexes away, starting nearby and working outward. If it finds a location with unobstructed line of sight (LoS) on an opposing unit, the mech moves there. When it has sight on multiple opponents, the AI chooses the closest target. In the case of a tie, it prefers to attack the weaker one (i.e. with lower health).


Terrain Effects

The following few days were spent introducing terrain-specific effects. This included filling out the placeholder code left inside CheckLineOfSight() that I had written into the AI's decision tree. I also introduced UI indicators, with red or grey line renderers representing open and blocked sightlines, respectively. Different terrain types also had distinct effects on movement. For example, a mech would be forced to walk over sand, could sprint over open grass, and could not traverse at all through bogs or dense forest. Each terrain type now had its own movement weight, which meant I needed to update my pathfinding algorithm from breadth first search (BFS) to an A* implementation. Finally, to convey these terrain distinctions to the player, I added a dynamic UI Info Panel that specifies the terrain type, movement, and line of sight effects for the current hex under the mouse.

Line Of Sight indicators

Blocked line of sight can preclude attacks, both by terrain type (such as dense jungle) or by other mechs. Color-coded lines and icons serve to convey these effects.


Wrapping Up

In the final days of the rapid-prototyping phase, I added the traditional "game wrapper" features and finishing touches. Upon launch, the game would now open to a Title Screen. During gameplay, hitting Esc would open a Pause menu with options to Resume, Restart, or Quit. Up to this point, I had deliberately utilized Time.deltaTime and Time.unscaledDeltaTime in the appropriate contexts to ensure that mech animations and effects would freeze in place when paused, while other functionality, such as UI effects, would continue uninterrupted. Despite the much more common case in game dev, this actually worked out exactly as intended on the first attempt, which was highly satisfying to see that foresight pay off. At this stage, I expanded the size of the map and implemented camera controls to allow panning and zooming. Finally, I added in win conditions and the associated end game UI.

Pause Screen

Walking animations and laser effects properly freeze and resume upon opening and closing the pause menu.


Acting on Feedback

As is always important to do in any game dev project, I made sure to find some friends to playtest the game to reveal bugs and identify issues in usability. Fortunately, the bugs were limited, although some prominent feedback I received on UX concerned the movement ranges of mechs. I had implemented a movement icon that would appear black & white over reachable tiles or red & black over non-reachable ones. However, these indicators would only appear when hovering over a given hex. The next most helpful quality of life (QoL) feature at this point would be representing all reachable hexes simultaneously (you know, like a traditional movement range display). So for the last day of my personal jam, I added a new function to the HexGrid class. Beyond just obtaining the set of tiles within a given hex radius, I needed to consider terrain movement weights, so BFS would not do. Furthermore, while A* provides a single destination, this use case needed to return multiple hexes. Therefore, this called for an implementation of Dijkstra's algorithm.

Movement Range

A unit's movement range is constricted by the terrain. While this mech can move two spaces away over sand, it can move up to three spaces away over grass.


Phase 1 Complete!

By the end of these two weeks, I had the basic trappings of a mech tactics game and was very pleased with the end result! If you'd like to check out the state of the project at the end of this phase, check out the download labelled Hex Tactics [Rapid Prototype] 2020-11-21.

As mentioned previously, I knew this project could be easily extended from here, and in the following weeks, I would add even more in terms of AI, polish, and even some procedural generation as well. Soon I will follow up on this post with some others describing those subsequent phases of the project.

[Next Post]

Get Hex Tactics

Leave a comment

Log in with itch.io to leave a comment.