Currently still a work in progress and subject to breaking changes. Visual State Machine is a Unity package designed to simplify the creation and management of state machines in Unity projects. It provides a visual editor for designing state machines, making it easier to create complex behaviors without writing extensive code.
vsm2_3.mp4
- Visual Editor: Design state machines using a user-friendly graphical interface.
- Unity Integration: Seamlessly integrates with Unity, allowing for easy implementation in your game projects.
- Custom State Support: Create your own states to handle specific game behaviors.
- Transition Management: Easily manage transitions between states with intuitive controls.
To install Visual State Machine in your Unity project, follow these steps:
- Open Unity and navigate to the Package Manager.
- Click on the + button and select Add package from git URL...
- Enter the following URL:
https://github.com/PaulNonatomic/VisualStateMachineV2.git
and press Add.
When upgrading to Visual State Machine V2 (VSM2) version 0.9.0-beta, follow these steps to ensure a seamless transition and maintain functionality within your Unity project:
- Commit Changes: Before starting the upgrade, ensure all your current work is committed to version control.>
- Update the package: to the 0.9.0-migration tag.
- Run the migration tool: from Tools -> VSM2 -> Migrate to 0.9.0-beta
- Update the package again: Once the migration has completed update the package to the latest, currently 0.9.6-beta
- Create a State Machine Asset
- In the Project panel, right-click and select Create -> State Machine -> State Machine.
- In the Project panel, right-click and select Create -> State Machine -> State Machine.
- Add States
- Either right-click and select Add State or drag out from the Entry State.
Usage.mp4
- State Selection Window
- The State Selection window appears listing all available states.
- States are grouped by namespace with the inbuilt states appearing at the top.
- The group of states nearest to the location of the state machine asset will open by default, but all states remain accessible.
- The State Selection window appears listing all available states.
- Create a Custom State
- Here's the built-in
DelayState
as an example: - Add a
Transition
attribute to an exposed eventAction
in order for it to appear upon the state's node in the State Machine Editor. - Serialized and public properties are also exposed in the state's node in the State Machine Editor. Note fields should be populated with value types and assets, not scene types.
- Here's the built-in
[NodeWidth(width:190), NodeColor(NodeColor.Teal), NodeIcon(NodeIcon.Clock)]
public class DelayState : BaseDelayState
{
[Transition(frameDelay:0)]
public event Action OnComplete;
[NonSerialized]
private float _elapsedTime;
[Enter]
public override void OnEnter()
{
_elapsedTime = 0f;
}
public override void OnUpdate()
{
_elapsedTime += Time.deltaTime;
if (_elapsedTime < Duration) return;
OnComplete?.Invoke();
}
}
- Assign the State Machine
- Create a GameObject with a StateMachineController component and assign your new state machine asset to it.
- Create a GameObject with a StateMachineController component and assign your new state machine asset to it.
- Run the Application
- With the StateMachineController selected, you can see the state of your state machine within the State Machine Editor window.
To pass data between states in the Visual State Machine, you utilize transitions. Transitions are defined by public event Actions that are decorated with a TransitionAttribute [Transition]. Here's how you can effectively use typed transitions:
-
Basic Transitions
- Use Action for transitions without parameters.
-
Typed Transitions
- Use Action to pass data between states. Note: The package currently supports a maximum of one parameter per transition. Action<T1, T2> or more parameters are not supported at this time.
public class SourceState : State
{
[Transition]
public event Action<int> OnTransitionWithInt;
public void TriggerTransition()
{
int valueToPass = 42;
OnTransitionWithInt?.Invoke(valueToPass);
}
[Enter]
public void OnEnter()
{
// Initialization logic
}
}
public class TargetState : State
{
[Enter]
public void OnEnterWithInt(int receivedValue)
{
Debug.Log($"Received value: {receivedValue}");
}
}
- Single Parameter Limitation: Currently, only one parameter is supported per transition. Ensure that your transitions use Action with a single type parameter.
- Entry Method Naming Convention:
- It's recommended to name your entry methods as OnEnter followed by the type, for example, OnEnterWithInt(int value). This enhances clarity and consistency.
- It's recommended to name your entry methods as OnEnter followed by the type, for example, OnEnterWithInt(int value). This enhances clarity and consistency.
- [Enter] Attribute Requirement:
- All entry methods must be decorated with the [Enter] attribute.
- Breaking Change: In version 0.9.0-beta and above, the OnEnter method is no longer abstract but virtual. If you do not override it and decorate it with the [Enter] attribute, it will not be called.
- Visual Indicators in the Editor:
- Any method decorated with the [Enter] attribute will appear as an input port at the bottom left of your state's node in the Visual State Machine graph, displaying the parameter type.
- Transitions are listed on the bottom right of your state's node with the corresponding type description for typed transitions.
- Connection Rules:
- Typed output ports will only connect to matching typed input ports.
- Transitions without types will only connect to input ports without types.
- When dragging out from an output port, valid input ports will remain highlighted while invalid ports are greyed out.
- Troubleshooting:
- If your entry method does not appear in the state's input ports list:
- Ensure you've added the [Enter] attribute.
- Verify that you're only using one parameter in your Action.
- If your entry method does not appear in the state's input ports list:
public class MultiplyState : State
{
[Transition]
public event Action<float> OnCompleteWithResult;
[SerializeField]
private float _multiplyBy = 2;
[Enter]
public void OnEnterWithFloat(float value)
{
var result = value * _multiplyBy;
OnCompleteWithResult?.Invoke(result);
}
}
public class ResultState : State
{
[Enter]
public void OnEnterWithResult(float result)
{
Debug.Log($"Received result: {result}");
}
}
By following this approach, you can effectively pass data between states in your Visual State Machine, enhancing the flexibility and functionality of your state-driven behaviors.
Add JumpOutState state and set it's Id. Then create a JumpInState with the corresponding Id to jump from one node to another.
Looping.mp4
The process of transitioning between nodes originally incurred no delay at all but when wiring up a looping state machine it could cause a stack overflow. To prevent this a delay of 1 frame has been added to all transitions by default, but this can be configured on a per transition bases by passing a frameDelay value through the Transition attribute, but please use with caution as a frameDelay of 0 can cause a stack overflow.
The State Machine Editor supports copy and paste within and between state machines.
CopyAndPaste.mp4
States have access to a shared data store
public class StateOne : State
{
[Transition] public event Action OnComplete;
[Enter]
public override void OnEnter()
{
SharedData.SetData("age", 42);
OnComplete?.Invoke();
}
}
public class StateTwo : State
{
[Transition] public event Action OnComplete;
[Enter]
public override void OnEnter()
{
var age = SharedData.GetData<int>("age");
Debug.Log($"StateTwo - Age:{age}");
OnComplete?.Invoke();
}
}
This same data store is exposed externally to the state machine through the StateMachineController.SharedData
VisualStateMachineV2 is licensed under the MIT license