A code-generated state machine including transitions, with support for Zenject.
This package has a hard dependency on Scriptable Object Collection, an amazing package by Bruno Mikoski. Please follow the installation instructions in the readme of that repository.
- The package is available on the openupm registry. You can install it via openupm-cli.
openupm add net.tnrd.statemachine
- Installing through a Unity Package created by the Package Installer Creator from Needle
- Installing through the Package Manager by Git URL.
- Open the package manager
- Click the plus symbol in the top left corner
- Select "Add package from git URL..."
- Paste this url: https://github.com/Thundernerd/Unity3D-StateMachine.git
- Click "Add"
This package works with Zenject. To enable this you have to add the Extenject package to your project through the package manager.
The reason you have to use the Extenject package is because the Zenject package is not available as a package.
To make a state machine you first have to create a state machine graph. You can do this by clicking your right mouse-button and selecting Create/State Machine Graph
.
This will create a new file that hosts the information to generate a state machine for you.
Once you have created a graph you are required to fill in some information:
State Machine Name
This is the name of the state machine and will be used throughout the generated files of the state machine. My suggestion is to use something that is relevant to the state machine as a whole.
Namespace
The namespace that will be applied to the generated code. Currently this option is mandatory, but future versions might see this changed.
Destination
This is the destination folder where the generated code for the state machine will be saved.
Use Zenject
With this toggle you can select if you want this state machine to work with Zenject or not. Please keep in mind that the two options are not compatible with each other, which means that switching this after you've already generated the state machine before could lead to issues.
To add a state you can click the button with the plus icon to the right of States
. This will create a new entry in the States
list.
You can choose a name for the state, and if the state is the initial state. There can only be one initial state, and that is the state that is first entered when the state machine starts.
To add a transition you can click the button with the plus icon to the right of Transitions
. This will create a new entry in the Transitions
list.
Please note that you need to make states first for transitions to work.
Once you have created a transition you have to first select the source for this transition. You can use the dropdown field to select a previously made state for this.
Once you have selected a source, you can add destinations by clicking the button with the plus icon to the right of Destinations
. Clicking this will show you a selection field where you have to select the destination state for this transition. You can only add each state once.
After you have followed the steps above, you should now be able to press the button that says Generate
. Once you click this, all the code necessary for using the state machine will be generated in the destination folder that you've provided before.
With Zenject
Once you have generated the code with the Use Zenject
toggle enabled, you will be able to use this state machine with Zenject.
To get started you will have to create an installer for your newly generated state machine. This installer is also generated for you, and you can easily create the installer by right clicking somewhere in your project view and selecting Create/State Machine Installers/_name of your statemachine_
.
This will create a Scriptable Object Installer for the state machine, and can be used with the contexts provided by Zenject.
Without Zenject
Once you have generated the code without the Use Zenject
toggle enabled, you will be able to use this state machine without Zenject, but through the use of regular Unity practices.
To get started you will need to add a component to an object in a scene. This component is automatically generated for you and will be named _name of your statemachine_Controller
. Once you have attached this script to a GameObject it will automatically create, initialize, and run itself.
To add functionality to the states you can simply open one of the generated state class files and add the code that you deem needed.
There are three pre-generated methods in every state class.
Constructor
You can use the constructor as you would any other constructor for any other C# class. This constructor will be called before the state is entered, and is therefore useful for initialization.
OnEnter
The OnEnter method is called when the state is entered. This means that this state is now the currently active state. You can use this method to execute state specific logic that should only happen when this state is active.
OnExit
The OnExit method is called when the state is being exited. This will be called before a new state is entered. You can use this to clean up everything related to your state.
Transitions are technically also states. They are states that live in between two normal states. These transitions can be used for all kinds of purposes.
Some good examples are:
- Playing animations
- Loading/unloading scenes
- Loading/unloading data from disk/web
- Preparing GameObjects for the next state
Or anything else that takes a longer (but not necessarily long) period of time.
There are two pre-generated methods in every transition class.
Constructor
You can use the constructor as you would any other constructor for any other C# class. This constructor will be called before the transition is entered, and is therefore useful for initialization.
StartTransition
This is the entry point for the transition. Here you can kick off routines, load/unload scenes, or prepare some data.
Once you have finished everything that this transition needed to do you can continue towards the next state by calling FinishTransition
.
When using Zenject it can happen that you want to access data from a scene in a state or transition. You are free to write your own solution for this, but, there is also a small helper component that can be used for this usecase.
Find a component that you want to be able to access from a state or transition and add the State Component Installer or Transition Component installer (respectively) to the game object. These components will be prefixed with the name of your state machine.
Drag the component you want to be available into the Component To Install
field.
If you want to bind any interfaces that are attached to this component as well, check the Bind Interfaces
toggle.
If you want to bind the component with a specific id, check the With Id
toggle, and enter the id in the newly appeared Id
field`.
Note that you cannot bind interfaces and bind with a specific id at the same time.
Next add states to the State Ids
list or transitions to the Transition Ids
list depending on which you have chosen. You can add as many states or transitions as you like.
Finally, to make the injection actually happen, add the newly added component installer to the scene context in your scene under the Mono Installers
section.
It is by no means necessary but if you feel generous you can support me by donating.
Pull requests are welcomed. Please feel free to fix any issues you find, or add new features.