How to Create a Simple Finite State Machine for 2D Games using Unity Scriptable Objects

Juan Manuel Orjuela
calendar_today
April 13, 2021
watch_later
minutes

Unity Scriptable Objects have become a game-changer in the world of game development. If you are a seasoned developer or a newcomer to Unity, understanding the potential of scriptable objects is crucial. In this tutorial, we will delve into creating an efficient finite state machine (FSM) using this powerful tool, enabling you to organize complex behaviors and maintain clean code for standout characters and enemies.

What is Unity3D?

Unity3d is a game engine with several years in the market. During these years, Unity has been improving its tools for programmers, like Unity Scriptable Objects, which gives them more flexibility to build videogames using good practices and cleaner architectures.

Unity Scriptable Objects

Let's talk about one of the tools that make our life as developers easier. The tool is called “Scriptable Objects” (SO). Scriptable Objects provide a structured way to organize and share data, settings, and functionality across different parts of your game. This can lead to cleaner code, easier debugging, and more scalable game development. They are particularly useful for creating reusable components, managing runtime data, and implementing design patterns. Additionally, we will discuss how it can be applied to create a finite state machine (FSM) using the example of a game that I’m currently developing called “Building Outbreak”.

What are Scriptable Objects?

A ScriptableObject is a data container in Unity that allows you to store and share data between different parts of your game. This container is a C# script that can be instantiated by a MonoBehavior to store the data. Unlike traditional MonoBehaviour scripts attached to GameObjects, ScriptableObjects are assets that exist within your project's folder structure. They are not bound to a specific scene or GameObject, making them versatile for various use cases.

Scriptable Objects Created
Figure 1. Scriptable Objects Created

What are the Advantages of using Scriptable Objects?

The Monobehaviours can be used as data containers. However, it has a big memory impact because when it is instantiated to access the data, it also gets a full copy of a game object to which the Monobehaviour was attached to. In other words, we get no needed data (like position, scale, and rotation of the object). On the other hand, when a Monobehaviour instantiates a SO, it only stores its reference, not a full copy.

It also helps the game architecture by separating the data and the game logic. It allows adding modularity to the game code, avoiding dependencies. This helps avoid global managers (singletons) and makes the unit testing easier.  

state machine controller
Figure 2. Scriptable Objects injection inside monobehaviour

How do the Scriptable Objects work?

Let’s explain it using the example of how the FSM was built for “BuildingOutbreak”, and a step-by-step guide on doing so.  

The best way to understand how the SO works is through an example. In this case, I’m going to show how the SO was implemented in “Building Outbreak”. The game is a 2D adventure game where the player has to escape from a building infested by zombies.

The zombies are “Non-Player Characters” (NPC), so they are controlled by artificial intelligence. For this game, the AI technique used was Finite State Machine (FSM), where the character changes its state according to the input from the virtual world.

For instance, if the zombie is currently in an “Idle” state and it detects the player (the player enters on its vision range), then its state changes to “chase”.


FSM
Figure 3. FSM for the zombie

Once the FSM is designed, then the SO can be created. To add a new SO, a class that extends from ScriptableObject class must be created. This new class represents a generic state, so it should be created as an abstract class as follows.

unity script
Figure 4. Base class for states using SO

As you can see, the SO can be used as a simple data container and also as a normal class with methods to manipulate the data internally. Now, let’s create concrete classes which represent the states by extending the class “State”.

create asset
Figure 5. Concrete class representing a state

Instantiating a SO could be made through the Unity Menu (as any other asset is created) by adding the attribute “CreateAssetMenu” with the path in the Menu where the new asset would be located. When Unity compiles the script, the asset should be located in the menu as follows.

building outbreak
Figure 6. SO creation as an asset in the menu


With those steps, all the states required can be found in the menu to be used in the game. Besides, the SO can be edited in the unity inspector as well.

SO in the Unity Inspector
Figure 7. SO in the Unity Inspector


In this stage, it is possible to inject the states to which the current one can travel (Figure 3). This helps low coupling between classes, and provides a tool for designers who can make changes from the editor avoiding source code changes.

Now we can create a mechanism to instantiate the states in a Monobehaviour. This should be a controller class that manages the state changes based on the events (rules) that the zombie gets (see the player for example).


FSM controller
Figure 8. FSM controller

The controller should be a Monobehaviour which will be injected in the “Enemy” class. This allows it to be used by all enemies that implement this class. The idea is that each enemy can execute its FSM according to its rules. For example, if a new zombie with more skills like run or attack by using objects is created, it can have its FSM set to run when it sees the player or uses a brick to attack instead of biting the player.  


“Enemy” class with its FMS controller.
Figure 9. “Enemy” class with its FMS controller

Finally, the controller has a method to execute the transition between states based on the rules. For example, if the zombie will attack, it should first check the rule which is being close enough to the player to bite him.

The transition method checks the nodes where the current one can travel (figure 3) and verifies the rules to validate if it can move to that state.

The SO is a tool that Unity provides as a data container to reduce the memory usage with unnecessary information. Also, it promotes modularity in the code, avoiding dependencies and global managers (singletons), which allows code reusability in other projects.  

Scriptable Objects can be used in many ways. It can be used for inventory systems for role-playing games, Pathfinding, game loading systems, player statistics systems, etc. Therefore,  you can think of building these systems to be reused in different projects.  

Finally, the SO is simple to use, therefore, it does not require much learning time, in addition to the good documentation and tutorials that Unity and other contributors publish for free.

Craft dynamic and engaging game behavior with unity scriptable objects. This powerful tool empowers you to seamlessly manage complex behaviors, optimize code organization, and unleash your creative vision. Elevate your game projects with unit scriptable objects, and experience the difference in managing your game's core mechanics.

ABOUT THE AUTHOR

Juan Manuel Orjuela is a software engineer and a game developer enthusiast. Juan had worked on different projects as a full-stack developer mainly using .Net technology. He also is a Google Flutter mobile developer. His passion for software development and video games led him to start creating his own games as a hobby with Unity 3D. His goal is to create his own game development studio.

Share Post

ARE YOU INTERESTED IN MORE ARTICLES LIKE THIS ONE?

Subscribe to our newsletter!

Interested in Augmenting Your Workforce with Lean Solutions Group

Fill in the information below to get started!