Writing Modular code with Unity Packages

by Hunter MacDonald TechnicalUnity

Hello! First, thank you for coming to my site and reading, here is a direct space to see updates on my games and some technical posts about what I do day to day. Today for my first real post I’ll be doing the latter.

I’m going to give you a technical walk through of some of my own modular packages that serve as a base for many game mechanics such as combat, and destructible elements. Hopefully by the end you’ll have an idea of ways you can organize your code and have your current game help your next game. To do this we can utilize the package manager in unity

Using the unity package manager is a great way to package up your code and getting started is simple. At its most basic, using the package manager in the engine is as simple as supplying a git URL and adding the package to your project. There are plenty of open source and free packages out there for you to use and perhaps even contribute to. And even more if you opt to use some open alternatives like the Unofficial Unity Package Manager Registry.

Let’s take a look at a very simple package I created that forms a core for a lot of game mechanics.

DamageReceiver is a simple package, on it’s own it is just a simple component to use for keeping track of health of any object.

    //DamageReceiver.cs
    public class DamageReceiver : MonoBehaviour, IDamageReceiver
    {
        public float health = 100;
        public float maxHealth = 100;
        public bool destroyed = false;
        ...

By adding some hooks to extend functionality, we can implement game logic for each game independently, and even package up other extensions ( Shields, Hit Effects, etc.) that can be included to extend functionality.

        //DamageReceiver.cs cont'd
        ...
        public Action<Vector2, IDamage> OnDamage;
        public Action<float> OnHeal;
        public Action<Vector2> OnDestroyed;
        public Func<IDamage, IDamage> OnProcessDamage;
        ...

using C# delegates, Action and Func, we can create programmatic hooks for our extensions to listen to and in the case of OnProcessDamage we are writing methods to modify values. This can be useful for creating shields or a defense stat. Another thing of note is we are using an interface to represent damage, this allows us to extend the data included in each damage message. Both of these patterns are useful for modular code, and can be used in contexts outside of DamageReceiver.

For instance, in Gunship I use a similar pattern to modify weapon damage.

    //Weapon.cs
    private Func<WeaponStats, WeaponStats> _statModifiers;
    public Func<WeaponStats, WeaponStats> ModifierFuncs { get => _statModifiers; set => _statModifiers = value; }

It's all a very code-first approach, but if you are designing modular tools in unity it's nice to be able to drop these components in and change behaviors by writing your own extension component. To take a more in depth look at the code have a look at Damage Receiver on github

In the future I will go into more examples of how I modularize my code. I'll be talking about more of my packages on github like

Thanks again for reading hopefully this short post was informative and gave you some insight into creating your own modular code.