Organizing Code with the Component Pattern and Inheritance

Blake Zoeckler
4 min readJun 1, 2021

--

In Galaxy shooter, all the enemies currently just run straight forward at the player. If they go off the left edge, they reappear on the right.

We want to create much more exciting and innovative forms of movement. Doing this will require more instance variables in the Enemy class, many more helper methods to control the enemy’s position, and would require a way for Unity to tell what type of movement we should use for which enemy.

We could just start dumping all this stuff into the Enemy class, but it would be a bad idea clutter it with a bunch of variables and methods. Most enemies will only move one way, so there always going to be tons of code that many enemies won’t use at all! This headache will only increase as we add even more movement and firing options. There’s got to be a better way.

There is, and it’s called the Component Pattern. This might seem familiar because most things we can attach to Unity game objects (like box colliders and audio sources) are called components as well. The idea here is to split the work of the Enemy script into multiple smaller scripts, and then mix and match the smaller scripts however we want to get exactly the right enemy to be instantiated in the game.

For now, we just want to add new behaviors to the enemies, so we should introduce a new EnemyBehavior class that will take care of any movement or laser firing that the enemies should be doing. We can remove all of the instance variables from the Enemy class that have to do with moving and firing lasers, and put them here instead. We’ll even add a helper function called FireProjectile that takes care of instantiating lasers.

There’s a lot of interesting declarations we’ve made here. Why are the class and Act method abstract? Why are some methods and variables protected or virtual? This is because we want to be able to utilize Inheritance and Polymorphism.

By default, all classes in Unity inherit from MonoBehaviour, and this allows their scripts to be attached as components to game objects. MonoBehaviour also includes standard methods like Start and Update that are automatically called at the proper times by the Unity engine.

However, we can make classes that inherit variable and code from something other than MonoBehaviour, including other classes we have written like EnemyBehavior. Usually inheriting from a class will copy everything from it, but there’s some limitations. The new class can only use variable or methods that a protected, while anything that is private remains unavailable. Also, we may want to change the functionality of methods that are inherited. The virtual keyword allows us to override a method so it does something different, and the abstract keyword forces us to do so, so we make sure we can’t forget to create a very important method like Act that makes the whole thing work!

Lets create another class called BasicEnemyBehavior that will implement the standard enemy behavior of just moving forward and shooting.

Even though we override Start, we can still use the EnemyBehavior.Start method by calling base.Start(). This makes use of all the basic setup that EnemyBehavior does. After that we can add necessary movement code, like setting the position of the enemy to the right location and starting the laser-firing coroutine.

We also make sure to actually create an Act method that actually does something. In this case it moves the enemy and causes it to warp to the right side of the screen if necessary.

New Enemy class variable
Enemy.Update change

Now we come back to why this is so useful. Now our enemy prefab will have two scripts attached to it. The Enemy script takes care of basic gameobject necessities like animation, and communicates with other managers in the game. Its EnemyBehavior script controls how it moves and fires its laser. Because they are part of the game gameobject, these scripts can easily communicate and affect each other. The Enemy.Update method calls EnemyBehavior.Act as long as the enemy isn’t dead.

The best part is that we can attach any kind of script we want as long as it inherits from EnemyBehavior. Now we can easily add all kinds of classes that can allow the enemies to move in lots of different ways. All of them are guaranteed to act the same way relative to Enemy, since we’ve guaranteed that there is some public Act() method that we can call. This kind of organization will definitely be worth it to keep everything nice and tidy in the future!

--

--

Blake Zoeckler
Blake Zoeckler

Written by Blake Zoeckler

I’m a passionate and talented software engineer seeking an opportunity in game development.

No responses yet