Now that I was starting to get some structure and progression into the game, I felt that it was time to elaborate a bit more on the enemy AI and the differences between enemy types. Currently I had about 8 or 9 test sprites in the game for different looking enemies, but they all used the same basic FSM (see here for how I went about that) and all had the same hitpoints and abilities. This lack of any differentiation contributed to the feeling of sameness that I'd been having while play testing, and so it was important to improve upon what I had, especially now that I was beginning to add structure to my game.
Improving things, however, meant planning, and so far I hadn't really given too much thought to the enemies in the game. Sure I knew I wanted them to be dumb and I'd written a basic FSM for them to use, but all games, no matter what style or genre, need the player to feel like they are progressing, that they're getting somewhere, otherwise boredom sets in. This also ties in with another thing I wanted to implement in the game, namely a bestiary. People like to collect things too, which is why games like Pokemon and Diablo are so good! They arouse our hoarding instinct and make us want to play just one more game to see what new creature or loot we can find. In my game I wanted to try to capture that feeling as best I could within the style of gameplay - and one of the ways I came up with was to make a bestiary that starts off empty and slowly fills up with every new enemy encounter. Before that though, I had to make the enemies different enough to warrant a page in that book, which meant looking carefully at what I had and starting to think ahead...
While looking at the sprites I'd already added to the game, I decided that they could be loosely split into different categories or "classes" based roughly on their body-type. My thinking here was that using classes would lower the number of enemy generators that I needed to have as I could just have a class specific set of generators that could spawn multiple enemy types within that class. This might seem a minor detail, but I wanted to have many different types of enemy in the game and I really didn't fancy having to make a unique generator for all of them! So, I loosely split the enemies into the following four classes:
- Undead - Skeletons, zombies, liches, etc....
- Insect - Spiders, beetles, scorpions, etc...
- Humanoid - Ogres, knights, elves, etc...
- Creature - Slimes, harpies, rats, etc...
Those four classes pretty much covered the whole spectrum of possible enemies in a fantasy game like Skein, and creating just four generator types would greatly simplify the graphics and the maze creation - Note, though, that I stuck to my modular approach to coding this, as I had ideas for other enemy classes and could see a moment when I wanted to add a new type of generator. After a bit of work in Photoshop and a couple of changes to my generation scripts, and the final graphics for each of the generator types were looking like this (I wasn't entirely happy with the undead and insect generators, as they are too similar in my opinion, but they'd do for now...):
Note that they glow too - might as well make use of the lighting engine I wrote! - with each generator having it's own distinctive colour (yellow, purple, red and green), and they will obviously deteriorate over time as they are hit by the player. This was simply a case of creating a few extra sub-images for each sprite to represent the damage, and then setting them based on the current hitpoints of the generator. I did this because I didn't want healthbars over everything as the view was already cluttered enough by the sheer number of enemies, but I needed something in the way of visual feedback to tell the player that they were having an effect with their hits. So, I made it that the generators have three "states" - healthy, damaged, very damaged, and each one would look like a slightly more broken and crumbling version of the previous one, until only ruins are left.
Although I wanted Skein to be more a shooter than an ARPG or true rogue-like, that didn't mean I wasn't going to have to create certain stats that would be expected in those genres - hitpoints, speed and damage would be the principle stats I'd need, but I also had a magic system in mind whereby the player could have a flaming sword (for example) and so set fire to the enemy. This meant I needed some extra stats for the effect being used and the duration of the effect. Given that I had added a class system, I also created a stat that held which class the enemy belonged too. I wasn't sure exactly what I was going to use this for, but it certainly seemed like something that could be useful to have when it came to magic, as I could maybe add in immunities to certain magic attacks based on the class, or even create class behaviours in the FSM scripts.
Setting these up was relatively easy as I originally had a single enemy object that I only had to change the variables for when it was created by the maze generation scripts. However, as I started thinking about more complex behaviours and the further possibilities of using magic and items, I took the decision to make an individual object for each and every enemy. It's a common belief that less objects in a game is better, but this is most definitely not true. Sure, the number of objects will affect the final size of your game by a few bytes, but it will have virtually no effect on how the game runs performance-wise, so if it's easier and more intuitive to use 20 objects rather than 1 object with 20 scripts, then do it! In this case, I kept the parent object and simply created children for each of the actual initial enemy types, which you can see here:
So what "types" of enemy were we going to have? Again, to simplify things, I strated by categorising the enemies further within their class, creating constants for shooting enemies, exploding enemies, melee enemies, and lobbing enemies. That last one "lobbing" is for enemies that are capable of lobbing bullets (rocks, fireballs, whatever) over the walls of the maze which was a feature of one of the most annoying enemies in the Gauntlet games, making it certainly something I wanted in my game. I knew at that time that I'd also want other possible types for magic or boss enemies, but I didn't add them in at that point as I didn't want to take on too much at once - but since I try to create everything in a modular way, it should be no problem to add these later as required.
I discussed the basic setup of the game's AI in the new update "They Live!" a couple of weeks ago, so I won't go into that here. Suffice to say that adapting the "melee" type to start shooting, explode when close to the player, or lob rocks at the player as they pass wasn't too hard and was mainly achieved by creating an "over-ride" event for the Step event of the child instances which replaced the relevant part of the parent object behaviours, although I did have to create a couple of custom scripts to handle things like the explosion AoE (area of effect) for the flying skulls.
Making Them Unique
Apart from the classes and the characteristics of the enemies in general, I also wanted each enemy to have something about it that makes it unique. This could be something simple like they are fast (spiders in the game are pretty nippy!), or that they can run away from you (skeleton archers will do that if you get too close), or that they can break down doors (ogres will hit doors if they are beside them and eventually break them down). Adding these details in required a bit of work revising the FSM scripts, but I eventually came away with a number of sub-scripts that would be called depending on the enemy object_index - see, it was worth the effort of making individual objects for each enemy!
When I was done setting that up, I was quite pleased with the results. Even with only ten or so enemies in the game so far there was enough variety between them to make playing the game more intersting, as the player now had to think a bit more about how to tackle each enemy type, taking the terrain and position of doors into consideration. Before moving on I did tweak the base stats one last time, adding some scaling to the initial hitpoints and damage of the enemies. Not much, since the game relies on numbers not strength to overwhelm the player, but I did make it so that some enemies on level three would take one hit to kill, but on level thirty they'd need two. It may seem like a tiny amount and hardly worth the bother, but if you have a hundred enemies with two hitpoints each, it's practically the same as having two hundred enemies!
After those changes, there was one final thing I felt needed adding at this point, and that was the ability for the maze generation scripts to create a Champion.
Apart from the base tier enemies, I also wanted to have two more tiers: Champions and Bosses. Bosses would have to wait until I was further along in the development due to them requiring more thought in how they are spawned and when - I want bosses to further break up the gameplay and present unique challenges at specific points in the game - but I wanted champions to be a part of the game almost from the start.
As you can see from the screenshot above, champions are bigger than standard enemies, and they also have far more hit points and do more damage. The idea being that some levels - specifically arenas and a random spawn in some regular dungeons - would have a champion to fight, and killing the champion would have some benefit to the player. Extra magic, huge amounts of loot or even a key to unlock a treasure room... I could use these for many different things! I also planned to give them special powers like auras to bolster the nearby enemies or attacks that do extra damage or set the player on fire. These things could wait for later however, as they would need to be tied in with the magic system, and I hadn't started working on that yet.
The Family Tree
With the addition of champions I had pretty much resolved the "family tree" of enemies:
- Each enemy has it's own Class
- Each class has it's own Type
- Each type has it's own unique strengths and weaknesses
What I wasn't 100% sure of yet was whether to create champions per class, per type or per enemy... With only four classes, that would make only four different champions in the game, which seemed like way too few. Basing the champions on type meant that I'd have more variety, since I'd have four times as many possibilities (each class has a number of types and there are four classes). Basing the champions on actual enemies would give the greatest variety and would certainly work well within the game, but I wasn't sure whether I wanted to create so many graphics for them. Making the base enemies was easy thanks to the sprites I'd licensed, but the larger sprites were my own work and so required more time, which I wasn't sure I was willing to spend yet.
I decided to shelve that problem for a later date (sticking with just one placeholder champion for now), since everything I had so far was working well. What I wanted to get to work on now was the UI. Since I'd had my crisis, I hadn't looked much more at the user interface and felt that it was time to get that sorted out once and for all...