Day 112 — Designing Enemies using Abstract Classes

Hey and welcome!

Now here’s something that I’ve been wanting to talk about for a while now. We’ve learned about classes and class inheritance before but an abstract classe is something a little new and now is the perfect time to use it as we’re going to be adding a few different enemies to our game.

Before we get onto abstract classes though let’s talk a bit about class inheritance in relation to our enemies here. We have 3 enemies to implement, a Moss Giant, a Spider and a Skeleton and we also have some shared properties among them. Instead of manually defining the properties for each of our enemy scripts we’re instead going to create a kind of global enemy script that the others can inherit which will look like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
protected int health;
protected int speed;
protected int gems;
public virtual void Attack()
{
Debug.Log("Enemy Attack");
}
}

The protected keyword here works similarly to the private keyboard but instead of only being able to change the value of it in the script that you’re currently in it allows any script that inherits this Enemy to change the value if needed.

After the properties we’re making use of something called a virtual method which lets any child classes that inherit this class to overwrite the method and change what it does.

Let’s see this inheritance in action though, go ahead and create a MossGiant script and add in this code:

public class MossGiant : Enemy
{
void Start()
{
Attack();
}
}

As you can see here instead of inheriting MonoBehaviour our script is inheriting our Enemy class instead. Right off the bat this gives our new script access to everything that we put in our Enemy class which is where the Attack() method in the Start() method is coming from.

If you create an empty object and call it Moss_Giant and add this script to it you can see the properties that it inherited as well by turning on the debug option for the inspector.

That’s definitely speeding up the process a bit and is a lot more optimised too since we’re using less code. What if however the Attack() method in the Enemy class doesn’t fit our Spider class that we’re going to create? Well luckily we made it a virtual method so we can overwrite what’s in there like this:

public class Spider : Enemy
{
void Start()
{
Attack();
}
public override void Attack()
{
Debug.Log("Spider Attack");
}
}

As you can see here we make use of the override keyword in order to change the Attack() method to our liking which we can call again by using the Start() method.

Abstract Class

Now this works out fine for us currently as we don’t need to worry about every Attack() method being unique and our different enemies can share them but what if we needed to implement a method that had to be unique for every enemy type and must be used?

Well that’s where abstract classes come in! To put this into better words our Moss Giant, Spider and Skeleton must have a method for handling their AI included and as you may guess it will need to be unique for each one as well.

Let’s go ahead and turn our Enemy class from before into an abstract class.

public abstract class Enemy : MonoBehaviour
{
protected int health;
protected int speed;
protected int gems;
public virtual void Attack()
{
Debug.Log("Enemy Attack");
}
public abstract void Update();
}

There isn’t anything too fancy going on here, all we need to do to make an abstract class is to add in the abstract keyword. Then when we want a method that’s forced on whatever inherits this class we use abstract again as seen for the Update().

public override void Update()
{
Debug.Log("Updating the Moss Giant...");
}

The above code here is what our Moss Giant and Spider classes will be looking for, without it you’ll get errors with the scripts. It must use override so that it becomes its own unique method as well, for the spider class you would change the debug text accordingly.

This update method is where we would put our AI logic for each enemy type. I got quite a bit of enjoyment from learning about abstract classes! If it’s a bit fuzzy for you at the moment we’ll be getting some good practice with them in the next articles as we piece together the AI for our enemies.

Hey and welcome! My name is Connor and my goal here is to put out a daily post for a full year about my game development journey.