-
Notifications
You must be signed in to change notification settings - Fork 2k
State Machine
A state machine is an object that can be in one of multiple states. Each of these states performs a specific set of actions, and can transition to different states based on predefined conditions.
In Chop Chop, we implemented a custom state machine solution based on ScriptableObjects, and we use it mainly to power characters (including the main protagonist). See below for details on the implementation.
This implementation is divided into two parts: the configuration, which happens at edit time and is based on ScriptableObjects, and the runtime part.
The ScriptableObject part of the implementation is a designer-friendly, modular way of building state machines. The ScriptableObjects are used to initialise the state machine with data, which means that by creating more instances of the same type you can give different values to them and create quantitative variations of the same behaviour.
-
StateSO: A
ScriptableObject
that can hold a reference to one or more actions (StateActionSO
). -
StateActionSO: A
ScriptableObject
that wraps a StateAction. -
StateConditionSO: A
ScriptableObject
that wraps a Condition. -
TransitionTableSO: A
ScriptableObject
that defines the Transitions of a state machine. This table "recaps" the structure of the state machine, and in fact we use it to display a custom editor window which allows you to have a complete overview of the state machine and all of its states, actions, transitions and conditions.
As an example, you can find the ScriptableObjects for the main character's state machine in the folder /ScriptableObjects/StateMachine/Protagonist/
.
The runtime part of the implementation has its name from being the one that contains the code that gets executed when in Play mode. Runtime objects are instances of plain C# classes, created from a corresponding ScriptableObject
(see above).
-
State: A class that contains multiple instances of
Action
andTransition
. TheState
is responsible for routing the callbacks from theStateMachine
to eachAction
andTransition
. This class is only used internally. - StateAction: A class that represents an action to perform. This is the base class all custom actions must inherit from.
-
StateTransition: A class that contains a target
State
, and a set ofCondition
that must be evaluated to transition to it. EachState
holds its ownTransitions
list. This class is only used internally. - Condition: A class that represents a conditional statement. This is the base class all custom conditions must inherit from.
-
StateCondition: A struct that holds a
Condition
and the expected result of the condition. This allows for reusability for when aCondition
should sometimes evaluate totrue
, and sometimes tofalse
. This struct is only used internally. -
StateMachine: The only
MonoBehaviour
, and the one that should be attatched to anyGameObject
that wants to make use of this implementation. It takes in aTransitionTableSO
, and, during itsAwake
call, eachActionSO
,ConditionSO
, andStateSO
in it is resolved into its runtime counterpart, and theTransitions
lists are generated. InUpdate
,Actions
of the currentState
are performed and thenConditions
of everyTransition
of the currentState
are checked. The firstTransition
that evaluates totrue
gets triggered.
To create a new StateSO
, simply open the Assets menu and navigate to Create > State Machines > State. Name your new State and then you can start adding actions to it. Note that the order in which the actions are displayed corresponds to the order in which they are performed; the custom editor allows for easy sorting so you can organize them accordingly.
To create a new Action
or Condition
script, in the Assets menu go to Create > State Machines > Action/Condition Script. This will create a new script from a template that will contain both the SO class and the runtime class. You can modify both classes to your needs. Remember that after creating the script, you need to create at least one instance of the SO to use it in your state machine. The template already adds the Asset menu item for you, under Create > State Machines > Actions/Conditions > Your New Script.
You can create a new Transition Table by opening the Asset menu > Create > State Machines > Transition Table.
From there, you can start adding transitions by using the Add transition button. Each transition needs a 'From State' and a 'To State'. 'From State' refers to the state the state machine should be in so that it can transition to the 'To State'. After setting them, you also need to add the conditions that must be met to make the transition happen. You can chain conditions with the And/Or option, and set whether the condition should be true
or false
, allowing for multiple scenarios in which the transition should take place. Once everything is set up, click on Add transition once again to confirm your changes.
The transition table is organized by 'From States'. This means that you'll see expandable groups with the names of the 'From States' as their headers, and expanding one will list all of the 'To States' it can transition to, along with their conditions. Transitions that take priority within a 'From State' should be sorted first, as they are checked sequentially and the first one that is met will trigger the transition. You can sort them with the up and down arrow buttons by the 'To State'. You can also remove a transition with the minus (-) button. Removing all the 'To State's from a 'From State' will remove the 'From State' from the table. You can also sort the 'From States'. However, only the first one is important to set up correctly as it will be the initial state of your state machine; subsequent ordering is purely preferential. And if you need to edit a State in your Transitions Table, besides finding the asset in the project window, you can simply click on the tools () button by the name of the State. This will display the State editor within the Table editor, allowing you to easily navigate back and forth between them.
You can edit your Transition Table in 2 locations: either (1) directly in the Inspector, by selecting the ScriptableObject asset in the Project window, or (2) with a custom-made Editor window which can be found under ChopChop > Transition Table Editor from the top menu. The window lists all Transition Tabels found in the project on the column to the left, for easy access.
This is what the Transition Table Editor window looks like:
And this is the same window while editing the Actions connected to a State:
Unity Open Projects - Open-source games made by Unity + the community
We are looking forward to see what you will create ❤
- the Unity Creator Advocacy team
- Game architecture overview
- Playing the game in Unity
- Creating a new playable scene
- Building the game
The game systems explained, with API examples. For programmers.
- Event system
- State machine
- Input
- Object pooling
- Runtime anchors
- Audio system
- Narrative
- Dialogue system
- Cutscenes system
- Inventory and Cooking
- Combat
- User Interface
How-tos for designers to expand the game's gameplay.
- Adding quests
- Adding items
- Creating dialogues
- Making a cutscene