Finite State Machine— Design Patterns for Unity #5

Make your code more efficient by useful patterns

OnurKiris
4 min readJun 21, 2022
Photo by Alice Butenko on Unsplash

Finite State Machine

As different features are added in your games in time, it will get more complicated to manage also. State patterns offers us opportunity to manage the rising complexity. To understand the main logic, first lets take a look what is state.

State

State can be defined by the current condition of an object or system. For example, some physical state conditions of your player like: Grounded, In Air or Crouching etc. or weather condition of your game atmosphere like: Sunny, Rainy, Snowy etc.

The point is what does state do? It decides the behavior of an object or system. For example, if your player ‘In Air’ state, it cant crouch or if weather is in ‘Snowy’ state, your player will start to freeze.

Picture from ashishvishwakarma.com

When Mario gets red flower, it transitions “Fire Mario” state and can throw fireballs.

The solution to these kind of complexity directing us to use Finite State Machine:

  • “Finite” means there are a limited number of states. For physical state conditions of player example, there will be three state as: Grounded, In Air and Crouching.
  • Only one state can be active at a time
  • States defines object behavior
  • States contains transitions between states

Lets say we want to set-up Finite State Machine for physical state conditions for player.

Diagram of transitions between states

According to above example diagram logic, follow below steps to implement Finite State Machine. I will share the codes of final form at the end:

  • Create ’PlayerStateManager’ script and attach it player game object.
  • Create ‘PlayerBaseState’ script. Delete MonoBehaviour inheritance and its methods. Make abstract class — (public abstract class PlayerBaseState)
  • Create state scripts like: ‘PlayerGroundedState’, ‘PlayerInAirState’, ‘PlayerCrouchingState’. In these scripts, delete MonoBehaviour and inherit from PlayerBaseState class.
  • In ‘PlayerBaseState’ script, create public abstract void methods as:

Now it will require to implement these abstract methods in the scripts that where you inherit from this one.

  • In those state scripts, implement abstract methods as public override methods which we fill inside them differently in each state script later.
  • In the ‘PlayerStateManager’ script, create variables that addressing related states and cache currentState variable in Start() method:
  • When the player instantiated, it will immediately call EnterState (Start()) method in GroundedState Class. You can fill inside of EnterState method like: play idle animation etc.
  • In the ‘PlayerStateManager’ script, we should also call UpdateState method of Grounded State Class in Update method so it will work every frame.

You can also fill inside of UpdateState method like ‘if press SpaceBar then Jump’ from Grounded State Class.

Diagram of transitions between states
  • Now before adjusting transitions between states, lets remind the relationship between them:

While in Grounded State, if you fall or jump, you will switch state to InAir or if you press ‘C’ key to crouch, you will switch state to ‘Crouching’. You can check the other transitions logic from above diagram.

  • As the last piece of our state machine, we have to make transitions. In the ‘PlayerStateManager’ script, create SwitchState method like:
  • For example, lets make transition between Grounded to InAir by pressing ‘SpaceBar’. In the GroundedState script, write the logic inside UpdateState method like:

And this was the last piece of Finite State Machine. You can improve it by adding additional methods like: OnDestroyState or OnCollisionEnterState in PlayerBaseState script and implementing to related scripts as your game logic need them. Make sure to calling these additional methods under correct MonoBehaviour method. For example, if you adding OnDestroyState method, call it in OnDestroy method from ‘PlayerStateManager’ script as you did for others. Here are the final codes:

PlayerStateManager.cs

PlayerBaseState.cs

One of the state scripts (same logic for the others): GroundedState.cs

This design pattern really helpful to manage things especially when your complexity rises and also supports some of SOLID principles like Single Responsibility Principle and Open / Closed Principle.

Thanks for reading!

Feel free to reach me out on LinkedIn if you have questions.

--

--