Dev Log
Strategy Pattern - Composition over Inheritance
The strategy pattern is a subtle pattern. It’s all about minimizing the duplication of code and decoupling classes. As an added bonus, the strategy pattern can also allow behaviors or algorithms to swapped at runtime without any messy switch statements or long chains of if statements. In the end it doesn’t have a super flashy or exciting outcome. It’s just good coding practice.
With some aspects of the pattern it’s easy to think, “Yeah, but this other way works…” But! The pattern is solid and avoids lots of little issues that can pop up later down the road when your project gets bigger.
Before we jump into the pattern lets first look at the problem it solves.
Inheritance Is Not Always Awesome
Let’s imagine you’re making a game based around weapons, or at least has a lot of them in your game. It would seem reasonable to create a “Weapon Base” class that other weapons can inherit from. This base class can contain basic stats and functions that can be used or overridden by sub-classes.
For example, we may have a DoDamage function that gets called every time a weapon is used. The function might simply reduce the health of the player’s target.
This is all reasonable.
Going a step further, let's imagine that we want to create 3 fire-based weapons that will all inherit from the WeaponBase and on top of reducing the targets health will also do some actions specifically for fire damage.
I now have 3 new classes that all have duplicated code. The DoDamage function has the same code from the base class, plus fire damage specific parts. Updating the fire behavior means opening and changing the code in all the every fire weapon class in your project. This isn’t horrible with 3 weapons, but imagine having 20 or 50 or 100 weapons. Yeah, that’s not going to work.
I could also call base.DoDamage, but then all my weapons would be dependent on the base class DoDamage function, which is definitely NOT AWESOME. If the base class function changes, all the inheriting classes change too and that’s not good. That’s not a solid foundation to build on. That’s a way to break your game in a hurry. This coupling between classes is what we want to reduce!
Now you might now argue that you could create a “Fire Weapon” class that inherits from the weapon base class and that all fire weapons inherit from… Which may work, but it is starting to get messy. Imagine now that you want to add ice or poision damage? You’d have to create Ice Weapon and Poison Weapon classes that those new weapons have to inherit from.
Okay, push comes to shove this might still be okay… Ugly, but okay, if the project stays small.
What if you now have a weapon that will do both fire and poison damage? Which class does it inherit from? Fire or Poison? Or do you make a combo class to inherit from? NO! Please don’t.
The strategy pattern can help solve these problems…
Strategy Pattern
The strategy pattern is all about encapsulating or wrapping up a behavior or algorithm in it’s own class. It’s also very closely related to the concept or belief that composition is better than inheritance! The exact details of how we do this are less important than the overall pattern so let’s start with a simple and common way to implement this pattern.
First, we create an interface called “IDoDamage” (you can argue all you want about using “I” to name an interface - I don’t care). This interface will have one function called “DoDamage.”
At this point, you might be thinking, “Okay, we’ll just implement the interface in all our weapons.” And that would be understandable, but it would be a mistake to do that as that would cause lots of duplicate code and not really buy us much in return from just good old inheritance.
Instead, we are going to create an instance variable of this interface in the Weapon_Base class. This class will also have a function that calls the DoDamage function on the IDoDamage variable.
Why? Good question. This is the crux of the whole pattern.
We can create classes that implement the IDoDamage interface. Each of these classes will have a different damage behavior. This will encapsulate the damage behavior AND make it so that we can change behavior at runtime by a simple assignment - no ugly switch statement or crazy chain of if statements needed.
For example, we can create a “FireDamage” class. This can do all the basic damage bits and most importantly it can then do any fire specific bits - maybe there are events that play sound effects or trigger specific lighting effects.
Then!
We create a new class for each weapon that inherits from Weapon_Base. Rather than hiding variables or overriding functions we use a constructor to set basic variable values AND to set the damageType variable.
While we now have a poop ton of classes, which could be a criticism of the pattern, we have very little duplicated code, and if we need to change the fire damage behavior, it only needs to be changed in one place in our project.
There is a neatness, a tidiness, a cleanliness that just feels good with this implementation. All we are doing is using a constructor to set up the weapon. The entirety of the damage algorithm or behavior is fully encapsulated in another class. While we are still using inheritance, we have decoupled much of our code, and much of the messiness of inheritance isn’t present in our solution.
Adding More Behaviors
The strategy pattern also works if you want to create other types of damage, such as IceDamage. To implement this style of attack, we need to create new IceDamage and IceSword classes.
Going Abstract
You could go either further and create generic weapons that have their damage and damage type set by a constructor. This could allow generic classes for each weapon type with all the data PLUS the behaviors injected into it.
Changing Behaviors
And I think the real cherry on top is that with the strategy pattern is that it allows easy changing of behaviors at runtime. Sure, you could do that with some if or switch statements. But those tend to be ugly. They break. They’re generally a brittle approach to programming and we can do better.
We can add a function to Weapon_Base to allow the damageType variable to be set. This would have the effect of changing behaviors. Something the code on the right.
Yes, I realize I made the variables public, but I don’t like changing values in classes from outside the class without using a function. If this was my project, I’d probably use private variables or maybe a public getter.
With this functionality, a click of a button or the invoking of an event can change the weapon's damage type and thus much of it’s behavior.
If that’s not useful. I’m not sure what is.
Combining Behaviors
What if you really want that fire poison sword? Maybe your game is based around combining behaviors or abilities? Then what?
Make a list of IDoDamage values. The code can then iterate through the list and called DoDamage on each item in the list?
I’ll be honest I haven’t tried this but it seems solid and pretty useful.
Other Thoughts
The choice to use an interface in the strategy pattern is not the only choice. You may want to use an abstract class instead so that you can define variables. Personally I like the cleanliness of the interface and then simply injecting any needed data.
I also thought to use scriptable objects. And while I think that would work, I think it’s stretching SOs to a place they don’t fit particularly well. Writing the classes and then creating assets seemed like too many steps and I was struggling to find a situation where that would truly be better. But maybe I’m wrong?
I also wrestled with making the base class a MonoBehaviour or not. For simplicity I kept it as a MonoBehaviour so I could easily attach it to a button (for the video). I think that choice really depends on the use, but my gut say most the time I’d want it to NOT be a MonoBehaviour.
The State Pattern
Whoa. It’s been nearly a year since I’ve made a post. I’ve been busy. A lot has happened, but that’s a topic for another post.
So I’m going to try something new, well a few things. But the first thing I’m going to try is writing a blog post for my next video. I figure taking the time to explain the video in writing will help me cement the ideas and provide one more resource for you all. There are many people who’d prefer to read than to watch a video. So maybe it’s a win-win? We’ll see.
But enough of that. Let’s get onto the second new thing.
That’s is exploring programming patterns. It’s something I’ve wanted to do because I want to learn more about programming patterns. Plus Bolt 2 will eventually (!!) get released and when it does many of the basic programming patterns will be far easier to implement AND folks developing with Bolt can benefit from implementing them.
Since Bolt 2 is now fully in hiding under the protection of Unity (who knows when the alpha will make it out to the public again) the upcoming video will be entirely C# based.
I should also give credit where it’s due. I’m no genius - that should be clear if you’ve read more than a few paragraphs of my writing. Much of what I know or think I know about programming patters comes from the book “Game Programming Patterns” by Robert Nystrom. It’s well worth a look if you are unfamiliar with the topic of programming patterns..
The State Pattern
“Allow an object to alter its behavior when its internal state changes. The object will appear to change its state.”
Like any other pattern the State pattern has its limitations, but also like any other pattern when used correctly it can help to detangle code which can make debugging code or adding features easier and much less frustrating. And that’s a win no matter how you look at it.
You may have heard the term “Finite State Machine” or “FSM” thrown around. Both of these terms refer to the same thing which is an implementation of the state pattern. The Unity asset Playmaker is based on the uses of FSMs and Bolt has the ability to create them with “State Macros.”
To help illustrate the state pattern, I’ve created a simple Unity project. There is a NPC played by a capsule and it’s goal is to wander around the maze and collect the yellow cubes. When it sees a red sphere (critter) it will chase it and attack it. Nothing too fancy.
So with that in mind, how would you program this behavior? Take a minute and think it through. No cheating!
Just about ready to go up on steam! ;)
This actually doesn’t look too bade with the use of functions… but will get out of control in a hurry.
I know when I first got started with C# and Unity, I would have done it with an if statement or two (or seven). And that works. It really does. Until you need to add another behavior. Or another game mechanic gets layered in. And we all know it won’t end there. The layers will continue to get added until the code breaks, bugs appear or the project gets forgotten because it was getting too hard to work with.
Simple FSM = Enum + Switch
So let’s look at the simple FSM. I still remember learning about this and was utterly confused by how to implement it but at the same time amazed at what it did to my code once I finally got it working. At that time I hadn’t really learned to use functions well so I had 100’s of lines in my update function. Needless to say it was nearly impossible to debug and when I discovered FSMs it was a major break through!
Simple FSM using an ENum and a Switch
In the case I described above the NPC behavior can be broken down into 3 different states or 3 different smaller behaviors. I thought of these as wander, collect and attack. A custom enum can then be created with these three values.
With the enum created a switch statement can be placed in the update function. For each case we can call the relevant function for that behavior. But we still need a way to change or switch (get it!) the state. For the most part this can still be done with basic if statements.
And now this may sound like we’ve back pedaled to our original solution and just made things more complex.
There is a major advantage here!
When we started, inside the update function we had to have a way to determine which state we were in - picking from ALL the possible states. Imagine how complicated that would be if there were 5, 6 or maybe even 10 different states. Yuck! Nothing clean about that.
With this method we only have to decide IF we need to change states GIVEN that we are already in a particular state. This greatly simplifies the decision making albeit at the cost of a few extra lines of code.
In a FSM it’s common that a given state can only transition to a limited number of other states. For example in my case maybe I don’t want the NPC to stop collecting if it sees a red sphere and it should only attack a sphere if it’s wandering around with no cubes in sight. If that’s the case the “state pattern” may actually reduce the amount of code needed as well as serving to untangle the code.
This implementation of the state pattern can be used for all kinds of different behaviors. It could be used to control animations, background music, or which UI elements are being displayed.
As an aside, in my personal project, I use a vaguely similar approach that makes use of a static enum and events for game modes so that various managers and UI elements can act or react based on the state of the game. The clarity of being in exactly one state has greatly simplified my code and made it far less error prone.
So this is all well and good, but you may be able to see the end result of this approach is still messy if the number of states starts to get large.
A Step Further => More Abstract + More Manageable
Having all the states switching inside the Update function can quickly get unmanagable and if nothing else is pretty hard to look at.
So let’s go one step further. This step adds another layer or two of abstraction to the system, still has some downsides but does clean up our code and will make larger FSMs easier to manage.
This step will place each state in its own (mostly) self contained class. The state will be in control of itself and will determine when to make a transition as well as determine which state to transition to.
Step 1 is to create a new interface. In my case I’ll call the interface INPCState. The interface will have just one function that will take in all the NPC data and will return a value of the type INPCState. This returned state will be the state for the next frame as the “Do Action” function will be called by the base class of the NPC which in turn will run the behavior for a given state.
The Wander State with all the functions included
Step 2 is to create a new class for each state of the FSM and that state needs to implement the interface INPCState. Each of these classes should also contain any functions or logic needed for that state. In my case I have choosen to leave all the variables on the NPC base class. This keeps each state class tidy, but does mean that the state class will be changing values on the NPC base class which is usually something I like to avoid - you win some and you lose some.
Inside each state’s “Do Action” function we need to call the relevant functions AND we need to decide which state to use for the next frame. You can see the full code to the left, but for now let’s jump back to the NPC base class which will help make sense of the return values.
Step 3 is to refactor the NPC base class. Here we need a new variable of the type INPCState that will hold a reference to the current state. We also need instances of each state - it would be possible to make this work with static classes and using an abstract class rather than an interface, but if you know what that means you can probably implement it yourself.
The simplified NPC Base Class
In the OnEnable function I’ve set the current state to the wander state to ensure that the current state variable is never null.
Then the real magic happens in the Update function. Here we have just one line! So awesome. Here we call the “do action” function on the current state and then set the current state to the value returned from that state.
That makes total sense, I swear it does, but it’s abstract.
Give a mintue to let it sink in.
This is so clean.
Step 4 is to add conditionals to the state classes to determine which state to be in for the next frame. Notice that we have passed in a reference to the NPC base class into the “Do Action” function and from there we can get a reference to the instances of the state classes.
Pro’s
The base class is exceptionally clean. You can now see how the class appears to change it’s state (behavior). Effectively the entire Update function changes depending on the current state and what in that state’s “Do Action” function. That’s cool.
If we want to add an additional state we simply create a new class, add an instance to the NPC base class and finally add conditions to allow a transition to the new state from other states.
As long as the number of states stays fairly small 5 or maybe 10 this is a pretty manageable solution.
Con’s
It’s hard to maintain if the system truly gets complex. In this case most sophicated structures such as behavior trees might be needed.
All the variables in the NPC base class are public. Which is a bit messy and not super awesome. This could be partially solved by creating a data container that itself is private in the NPC base class but has public variables… This passes the buck a bit, but would prevent those variable from being changed by classes without access to the data container. A generic data container would also potentially open the doors a bit wider for reuse of the states by other NPC types - so worth thinking about.
As mentioned before, the states are changing values of variables on the NPC base class. Not ideal and something I usually go out of my way to avoid if possible.
Easy UI Styles for Unity
So like many of us when in the middle of the project it’s easy to get distracted and start building tools that probably take longer to create than the time the saved by the tool. And what do you know, a few years back I created Easy UI Styles…
I was finding it hard to iterate on my UI designs. I’d change a color here and it would look better, but then I’d need to change it 7 other places and then it was a tad or dark. Or a tad to light. Oh and then I wanted the font a bit smaller.
Ugh.
So Easy UI Styles let me define a style in a custom editor and then apply it object by object in the scene.
A little while back I started switching my project from UGUI text to Text Mesh Pro (holy crap it looks better) and Easy UI Styles didn’t support it. So down the rabbit hole I went! Several hours later the asset now supports 99% of the setting for Easy UI Styles - seemly there are 2 settings that can’t be set by an external script.
While I was at it I created a new video for the asset as well as a cut down free version of the asset. You can get the “Lite” version on the asset store once it’s accepted or until then you can download it here. The full paid version is free for my Patrons (wink wink).
Older Posts
-
April 2024
- Apr 10, 2024 Ready for Steam Next Fest? - Polishing a Steam Page Apr 10, 2024
- Apr 1, 2024 Splitting Vertices - Hard Edges for Low Poly Procedural Generation Apr 1, 2024
-
November 2023
- Nov 18, 2023 Minute 5 to Minute 10 - Completing the Game Loop Nov 18, 2023
-
September 2023
- Sep 13, 2023 Visual Debugging with Gizmos Sep 13, 2023
-
July 2023
- Jul 4, 2023 Easy Mode - Unity's New Input System Jul 4, 2023
-
May 2023
- May 19, 2023 Level Builder - From Pixels to Playable Level May 19, 2023
-
April 2023
- Apr 11, 2023 Input Action in the Inspector - New Input System Apr 11, 2023
-
February 2023
- Feb 26, 2023 Tutorial Hell - Why You're There. How to Get Out. Feb 26, 2023
-
December 2022
- Dec 31, 2022 Upgrade System (Stats Part 2) Dec 31, 2022
-
November 2022
- Nov 10, 2022 Stats in Unity - The Way I Do it Nov 10, 2022
- Nov 5, 2022 State of UI in Unity - UI Toolkit Nov 5, 2022
-
August 2022
- Aug 17, 2022 Knowing When A Coroutine Finishes Aug 17, 2022
-
April 2022
- Apr 23, 2022 Unity Input Event Handlers - Or Adding Juice the Easy Way Apr 23, 2022
-
March 2022
- Mar 15, 2022 *Quitting a Job I Love Mar 15, 2022
-
February 2022
- Feb 8, 2022 Split Screen: New Input System & Cinemachine Feb 8, 2022
-
January 2022
- Jan 24, 2022 (Better) Object Pooling Jan 24, 2022
- Jan 19, 2022 Designing a New Game - My Process Jan 19, 2022
- Jan 16, 2022 Strategy Game Camera: Unity's New Input System Jan 16, 2022
-
December 2021
- Dec 16, 2021 Raycasting - It's mighty useful Dec 16, 2021
-
November 2021
- Nov 22, 2021 Cinemachine. If you’re not. You should. Nov 22, 2021
-
August 2021
- Aug 3, 2021 C# Extension Methods Aug 3, 2021
-
June 2021
- Jun 27, 2021 Changing Action Maps with Unity's "New" Input System Jun 27, 2021
-
May 2021
- May 28, 2021 Unity's New Input System May 28, 2021
- May 8, 2021 Bolt vs. C# - Thoughts with a dash of rant May 8, 2021
-
March 2021
- Mar 10, 2021 Coroutines - Unity & C# Mar 10, 2021
-
January 2021
- Jan 14, 2021 Where's My Lunch? - January Devlog Update Jan 14, 2021
-
December 2020
- Dec 27, 2020 C# Generics and Unity Dec 27, 2020
- Dec 7, 2020 Steam Workshop with Unity and Facepunch Steamworks Dec 7, 2020
-
November 2020
- Nov 27, 2020 Simple Level Save and Load System (Unity Editor) Nov 27, 2020
- Nov 9, 2020 Command Pattern - Encapsulation, Undo and Redo Nov 9, 2020
-
October 2020
- Oct 28, 2020 GJTS - Adding Steamworks API and Uploading Oct 28, 2020
- Oct 9, 2020 Game Jam... Now What? Oct 9, 2020
-
August 2020
- Aug 16, 2020 Strategy Pattern - Composition over Inheritance Aug 16, 2020
-
July 2020
- Jul 24, 2020 Observer Pattern - C# Events Jul 24, 2020
- Jul 15, 2020 Object Pooling Jul 15, 2020
- Jul 3, 2020 Cheat Codes with Unity and C# Jul 3, 2020
-
June 2020
- Jun 16, 2020 The State Pattern Jun 16, 2020
-
August 2019
- Aug 12, 2019 Easy UI Styles for Unity Aug 12, 2019
-
July 2019
- Jul 3, 2019 9th Grade Math to the Rescue Jul 3, 2019
-
June 2019
- Jun 12, 2019 Introducing My Next Game (Video DevLog) Jun 12, 2019
-
May 2019
- May 29, 2019 Programming Challenges May 29, 2019
-
March 2019
- Mar 2, 2019 Something New - Asking "What Can I Learn?" Mar 2, 2019
-
November 2018
- Nov 30, 2018 A Growing Channel and a New Tutorial Series Nov 30, 2018
-
October 2018
- Oct 11, 2018 Procedural Spaceship Generator Oct 11, 2018
-
July 2018
- Jul 11, 2018 Implementing SFX in Unity Jul 11, 2018
-
May 2018
- May 31, 2018 Prototyping Something New May 31, 2018
-
April 2018
- Apr 17, 2018 When to Shelve a Game Project? Apr 17, 2018
-
February 2018
- Feb 9, 2018 State of the Game - Episode 3 Feb 9, 2018
-
December 2017
- Dec 16, 2017 State of the Game - Episode 2 Dec 16, 2017
-
November 2017
- Nov 7, 2017 The Bump From A "Viral" Post Nov 7, 2017
-
October 2017
- Oct 30, 2017 NPC Job System Oct 30, 2017
-
September 2017
- Sep 1, 2017 Resources and Resource Systems Sep 1, 2017
-
August 2017
- Aug 3, 2017 State of the Game - Episode 1 Aug 3, 2017
-
June 2017
- Jun 20, 2017 Resources: Processing, Consumption and Inventory Jun 20, 2017
- Jun 15, 2017 Energy is Everything Jun 15, 2017
-
May 2017
- May 16, 2017 Graphing Script - It's not exciting, but it needed to be made May 16, 2017
- May 2, 2017 Tutorials: Low Poly Snow Shader May 2, 2017
-
April 2017
- Apr 28, 2017 Low Poly Snow Shader Apr 28, 2017
- Apr 21, 2017 Environmental Simulation Part 2 Apr 21, 2017
- Apr 11, 2017 Environmental Simulation Part 1 Apr 11, 2017
-
March 2017
- Mar 24, 2017 Building a Farming Game Loop and Troubles with Ground Water Mar 24, 2017
-
February 2017
- Feb 25, 2017 The Inevitable : FTF PostMortem Feb 25, 2017
-
December 2016
- Dec 7, 2016 Leaving Early Access Dec 7, 2016
-
November 2016
- Nov 28, 2016 Low Poly Renders Nov 28, 2016
- Nov 1, 2016 FTF: Testing New Features Nov 1, 2016
-
October 2016
- Oct 27, 2016 Watchtowers - Predictive Targeting Oct 27, 2016
- Oct 21, 2016 Click to Color Oct 21, 2016
- Oct 19, 2016 Unity Object Swapper Oct 19, 2016
-
September 2016
- Sep 18, 2016 Testing Single Player Combat Sep 18, 2016
-
May 2016
- May 25, 2016 Release Date and First Video Review May 25, 2016
-
March 2016
- Mar 26, 2016 Getting Greenlit on Steam Mar 26, 2016