Sunday, May 3, 2020

Bleaktide Part 4: Game Development Process

Note that this is part 4 of a series. In this installment I'll start discussing some of the more technical and design related aspects of the game.

Up until now I've discussed the mood and theme and mostly just posted screenshots to give an overview of the game. In this post I'll begin to incorporate some technical game development aspects into the write-up, though I'll try to keep it brief and not get bogged down in detail.

The game is being developed in the Unity engine using the C# language. I refer to characters as 'units', mostly because some of the code I brought in at the beginning was re-used from one of my previous real-time strategy games (where individual characters are generally referred to as 'units').

There is a massive amount of logic associated with each unit, and not all units share all logic. For example, villagers don't have abilities, playable characters aren't autonomous and don't require 'brains', and monsters don't hold conversations. So my unit framework consists of a core Unit class and then a collection of unit component classes, each of which handles a specific aspect of that unit's behaviour. Below is a screenshot showing all of the components attached to the Crypt Lord prefab.

A list of the components attached to the Crypt Lord unit, one of the playable character types. Each of these is a single C# class responsible for one aspect of the character's overall behaviour.

Monster Setup

So far there are about 22 monster types in the game, though only about a 3rd of these have actually been implemented (the rest cannot be used yet). There is a fair bit of setup for each monster type -- their materials and textures need to be modified to fit the common look and feel of the game, their animations often need to be setup and tweaked, and there is a lot of common unit setup (as illustrated in the image above) which needs doing before they become operational.

Unity has an old legacy animation system, and a newer, more powerful animation system called Mecanim. Nowadays most character models are setup to work with Mecanim, but occasionally you'll encounter models that still rely on the legacy system. I wrote an animation system that wraps this functionality so that it doesn't matter which format is used.

This is my monster animations test scene. It allows me to transition between animations using the buttons at the bottom to ensure that transitions are all smooth and that the animation speeds / durations are to my liking.

Unity's Mecanim animation framework relies upon state graphs called 'animator controllers'. Whilst powerful, they require a lot of work to setup and it can be difficult to get the exact behavior you want, especially when you have dozens of characters to setup. Over time I decided to forego the use of animator controllers and to rather handle smooth transitions between states using my own framework.

An example of a Mecanim animator controller graph. They can get much, much more complicated than this.

I prefer a simpler approach where I decide beforehand all of the possible animations characters will need (and the settings required to get the desired behavior). I won't go into detail, but a screenshot of the setup panel should give some idea of what I mean...

This is the animation setup for a monster called a 'Jungle Durg'. It uses the legacy animation system but setting it up for the modern Mecanim system is identical using my framework.

I'll just throw in a screenshot of a few more monsters to pretty this post up a bit and not bog it down with too much technical information. Click the image to get a zoomed in few.

Monsters behave in a pretty simplistic, predictable manner at the moment. I may expand upon this aspect and introduce more complex behaviors later, but for now the system I have in place does the trick. Each monster is controlled by a class called the 'Monster Brain'. It handles things like checking whether there are any enemies in sight or whether it can hear anybody.

It has a vision arc in front of it that allows it to detect you at a distance if you walk in front of it. However, monsters have a limited hearing range and so you can sneak past them from behind if you're careful.

Some monsters are cowardly and will run away if it looks like they're going to lose a fight. Monsters will also attempt to rally nearby allies to come to their aid.

These are the settings currently available for setting up a monster's 'brain'. Still pretty simple at this stage but it does what I need it to.

Monster Combat

Engaging in combat with fearsome creatures is, of course, a core part of the game. Slaying them gives you valuable experience points and loot. You'll often find yourself surrounded as monsters rally allies to their aid and so you'll need to rely on your abilities, potions and brews to buff yourself and deal additional damage.

The montage below shows the Dark Templar using an ability called the 'Shield of Ghaz'kar' to protect himself (and nearby allies if any were present) from the Roach Khan about to attack him.

When monsters are slain they can potentially drop loot. To some extent this is randomized, however there must also be some designer input into this process so that the items they drop are thematically relevant (and it's especially important for quest related items). Below is an example of my setup for specifying the list of items a monster can potentially drop.

I think I'll call it at that for now, this post is getting long. I'll be sure to include more technical information in future posts. In the next installment I introduce some of the gameplay features I'm working on...