Subterrain
Subterrain#
Subterrain is a PvPvE turn-based underground city builder with gameplay comparable to Sid Meier’s Civilisation 5 & 6.
This was worked on for about 1.5 months, and I eventually stopped working on it due to the design needing more work. Originally, the game was a purely PvP game with no AI opponents. While playable, it simply wasn’t fun due to the combat not having the required nuance, and it being difficult to find players. This is why one of the attempted changes was to pivot the game to have the Dark Ones, which was an empowered AI opponent that would attack all the players, and if the boss enemy was defeated, the player who achieved the final blow would win the game. The boss enemy is always visible on the map and doesn’t move, which gives all players far more direction in what to do. This would help fix the issue of players finding each other as they are likely to encounter each other around the boss enemy, as well as giving the game more options for players to win, unlike before, where the only two methods were to kill all the remaining players or find 3 artefacts hidden within the map.
Unfortunately, strategy game AI is typically very challenging to get right and especially problematic to get the AI to be good. I was aware of this when working at Nomad Games Ltd, when working on the AI for the Cities and Knights expansion, so I tried to sit down and create a list of aims that the AI would do and what it would prioritise if it could do multiple actions. While this is a good first step and would help get the AI to function and to not get lost during this process, I fear it would end up with the same problem as many previous AIs in strategy games, which is that they are not good or enjoyable to play against. While the AI could be functional but not very good, this could be ‘fixed’ by buffing the units and how many they have to help make it more challenging and stop the player from punishing it as much. But this is typically not fun to play against in various titles that did this, and returned us to the original issue, which is that the combat just is not fun.
But onto the implementation of various systems and mechanics, as this project does have various good parts, even if the game itself was not terribly fun.
Networking#
The multiplayer was done through Netcode for Gameobjects, which is a Unity package which allows for easier creation of multiplayer games.
Fortunatly due to this being a turn based game I could just do a server authoritive model which is ideal for a PvP game as this would reduce the oppotunity for cheating significantly (Though a lot more would have to be done to minimize it) and it also simplifys implementation of clients as clients would just be requesting for actions to be done and everything being processed on the host machine. And finally, I also wouldn’t require doing any client prediction, which, while I have dealt with it before, does add complexity to any project.
For keeping the various player units in sync and allowing the player to request them to do various actions, they all derive from a ‘PlayerObject’. Which handled what type of object it is, health, damage, sight range, etc. and for the derivatives, they would only hold additional actions or stats required for them. For example, the miner would have its mining functions within a derived script, as it has no reason to be added to every object in the game.
The ‘PlayerObject’ having the ‘ObjectType’ also allows for stats to be loaded from a configuration JSON file, so the stats such as health, sight range, etc. can be set from a json file which is far more convient for testing as the file can be easily updated after the project was built and easier to manage in a project and source control in general.
Level#
Due to the game being underground, this allowed for one of the major features of the game being verticality, allowing players to move between layers and fight each other on different levels.
The levels are predefined using a text file like this:
XXXXXXXXXXXXXXXXXXXXXXX
XXxxXXXXXXXXXXXXXXXXXXX
XXXxxXXXXXXXXXXXXXXxxxX
XXXXXXxxxxXXXXXXXXXXXXX
XXXXXXXXXxxxXXXXXXXXXXX
XXXXXXxxxxxxXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXX
-
XXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXxxxxxX
XXXXXXXXXXXxXXXXXxXXXXX
XXXXXXXXXxxxXXXXXxxxXXX
XXXXXXXXXXXXXXXXXXxxxXX
XXXXXXXXXXXXXXXXXXXXXXX
‘X’ capitalised indicates a wall, and ‘x’ lowercase indicates a moveable area and the ‘-’ indicates a new layer. Typically, it would be five layers being listed here, but this is just a small example. Additionally, the levels don’t require the layers to be even the same size or shape, as this is handled and intended in their original design.
While the map is being loaded, various hexes would be chosen to be coal, sulfur, or iron hexes. These can be used by miner structures to improve production and/or science of hovels.
As the level allowed for digging through the map meant that the level would need to stay in sync for all players at all times. I did this by keeping a HashSet of the modified hexes themselves. Then, on the next network tick, it would attempt to send the modifications to each of the players. Which does work in a perfect world where no packets are lost, but in testing, this was revealed to have issues, as if a packet was dropped, the level would be out of sync. This was fixed with a simple confirmation check that the clients would send back to make sure the level changes were received.
Coordinates#
When doing hex grids, you will typically find either Offset, Cube, Axial, or Doubled coordinates. There is inevitably more, but these are the most common. In the project, the maps use Offset coordinates for storing them and are generally easier to work with in my head, but most of the calculations are done with Cube coordinates.
While I could explain coordinates and the various calculations done within the project, this excellent website, which I used as a source for most of my implementations used within the project: https://www.redblobgames.com/grids/hexagons/
City Building#
The buildings are also based on the ‘PlayerObject’s and upon placement would update with their closest city on their layer. There is also a special structure called a pipe, which boosts production of miner structures as well as allows the pipes to connect to specific cities, no matter the distance.
Screenshot of Ingame#
Unfortunately, I didn’t take many screenshots of the project earlier in the production, but felt the post required at least a screenshot of the project.