Flow Actions
Flow actions are scripts that can be assigned to nodes. Using the State Action (GameSuite) node type, you can define what logic should execute OnEnter, OnUpdate and OnExit.
Duplicating actions
To copy paste an action, click on the βοΈ icon and select Copy
.
Then on another node (or the same) press Assign Action Task
and scroll all the way to the bottom to the Paste
entry.
Objects
Spawn Objects
Spawn objects from GameResources, these are GameObjects and can come from Resources or Addressables. This is not just limited to UI.
Attributes:
- Load Async: Instantiate the object asynchronously, this will not stall the main thread and have smooth performance, but it could take several frames for the object to spawn.
- Allow Spawn Duplicate: By default, the Spawn Objects action does not spawn another instance if it already exists.
- Parent: Select under which GameObject these objects should be spawned. The parent is configured through the Object Finder.
- Objects To Spawn: Define which GameObjects should be instantiated in this task.
Spawn Objects (from Resources)
This behaves mostly in the same way as Spawn Objects, but this only loads from Resources in the traditional way. This action is meant for instantiating objects while the Addressable system is not initialized yet. The regular Spawn Object action will wait for the AddressableService to be initialized before it will spawn its objects, this Spawn Objects (from Resources) action does not have to wait and can spawn objects immediately.
Avoid use after splash screen
Only use this for the first splash screen node. After the AddressableService is initialized, always use the regular Spawn Object action throughout the app.
Destroy Objects
When adding the Spawn Objects action to a node, a Destroy Objects action will be added automatically on node exit. In most use cases, this is the desired behavior.
By default the Destroy Spawned By Node
value is enabled, which will remove all objects which got spawned from any Spawn Objects actions added to this node.
When manually specifying the objects to destroy, it will destroy a single instance if it exists. Enable the Destroy All Instances
option to remove all spawned instances of that objects which have been spawned during the lifetime of the app.
Object lifecycle management
If you want to keep the GameObjects alive after the node exits, just remove the Destroy Objects action from OnExit to persist the objects spawned by the node. This allows for for example to spawn assets at the start of a flow and destroying them when exiting the flow.
Scenes
Scene Loader
Pick a scene to load, loading scenes can either come from addressables or from the build menu. The flow action ends when the scene is loaded and activated.
Execute the action in a sequence and add further actions required after this flow action, or add an OnFinish transition going out of this node when the game should proceed.
This is useful for showing a loading screen while the game is loading.
From Blackboard
When disabled, it shows the default scene selector dropdown. If the scene has to be loaded dynamically, like from a level select, then use the From Blackboard option to point to a Blackboard string variable which has the name of the scene to load.
This script could be placed on a button of a level select. It shows the scene select dropdown in the inspector and sets the blackboard variable with that scene name.
public class SceneSelector : MonoBehaviour
{
[Scene]
public string SceneName;
public string VariableName;
public void SetScene()
{
Services.Get<FlowService>().Blackboard.SetVariableValue(VariableName, SceneName);
}
}
Async Loading
Load the scene on the main thread and thus blocking unity while loading the scene, or when enabled, it will load the scene in the background, while unity keeps playing. This is useful if the game should remain to run smooth or when there are animations playing which have to keep updating while the scene is loading.
Wait for object loaders
This checkbox allows for recursive object loading, like when a scene has to instantiate NPCs and other objects. Implement the ISceneObjectLoader
interface to any components in the loaded scene and invoke the ObjectLoaded
callback when finished loading. Make sure to also return true to IsLoaded
when the loading has completed.
public interface ISceneObjectLoader
{
bool IsLoaded { get; }
event Action ObjectLoaded;
}
Recursive loading
Create complex loading logic by creating a ISceneObjectLoader
which loads another ISceneObjectLoader
etc. This allows for recursive loading objects, audio, libraries, downloading assets from online, waiting for a backend connection or any other process which takes longer time.
A simple example is a character, which in turn has to load its audio, outfit and weapon graphics models.
Scene Unloader
This action works in conjunction with the Scene Loader. The flow action ends when the scene has been completely removed.
From Blackboard
Works the same as the Scene Loader, to allow for dynamically loading and unloading scenes. This is again useful when entering a game sub flow, where you load the scene in the first node, and unload the scene when exiting the flow.
Clear memory
It is advised to set the node to execute in sequence and add an Unload Unused Assets
flow action behind it to clear up any reserved memory.
Flow Interactions
Send Event
Next to sending flow events from components or code, the FSM itself can also send them. This is mostly useful when having to send events to a specific target flow or parent flow.
Activate Previous Node
Activate a previous node in the breadcrumb history of the app. You can set how many steps it should jump back in a particular graph. This allows the user to go back to the menu it came from if the menu flow is very complex with lots of hierarchy trees to navigate. It allows to go back in the Owner, Parent and Specific target graph.
Services
Call Service Method
Invoke a method in any service. At the moment, this only allows calling methods without parameters.
Initialize Services
Start initializing the services, this can be placed in the first node. When adding the All Services Initialized condition, this action is not required as it already starts the initialization process.
Reset Service
Choose which services should be disposed of. The next time these services are accessed they will be recreated.
Libraries
Cache library assets
Loading library assets for the first time requires them to be downloaded, unpacked and loaded into memory. Although this is very fast in most occasions, you might have a large library of assets, such as NPCs, weapons or power-ups.
To cache assets of a library in a loading screen and make sure all data is instantly available at anytime, add the Cache Library Assets
flow action and set the Library type from the dropdown.
Analytics
Send Analytics Event
Send analytics events through the application flow.
Send on exit
You can send an analytics event when entering a node and then another one when exiting, this allow for example tracking when someone exits the game node, regardless if it was won, lost or quit for example.
Timer Start
Timers can be used for analytics tracking. Enter the name of the timer that should start running and use the same name in Timer Pause and Timer End.
Timer Pause
Pauses a timer which can re resumed with the Timer Start flow action.
Timer End
Stops the timer and sends an analytics event with the attached time. See the analytics chapter to read on more details on analytics.
Audio
Music
Play Music
Play a specific music track and set the fade time. Check the Conditional Actions chapter to learn how to create more advance behavior.
Resume Music
The previous music playing will resume playing. This allows a separate music track when entering the menu and going back to the game resumes the last playing music. This also allows to set a manual fade in and out time.
Pause Music
Pauses the currently playing music so it can be resumed later. Has fade time.
Stop Music
Stop playing the music with a fade time.
Sfx
Play Sfx
Play a sound effect. Check the Conditional Actions chapter to learn how to create more advance behavior.
Stop Sfx
When a sound effect is looping, like an ambient sound, use this to stop playing the looping sfx.
Miscellaneous
Conditional Actions
These allow running any custom code by checking if a condition (or multiple) are valid. It can also be used as a toggle, read the Conditional Actions chapter to learn more.
Unload Unused Assets
This action will try to unload different assets of the game:
- It calls Unity's
Resources.UnloadUnusedAssets()
- Collect Garbage using
System.GC.Collect()
- Removes unused resources
- Removes unused audio assets
- Addressables clears pre-cached assets
When you need to clear any kind of assets yourself, subscribe to the UnloadAssets
event like this example:
Services.Get<ResourceService>().UnloadAssets += Unload;
private void Unload()
{
// Add specific asset unloading.
}
Addressables Cache Resources
Select the addressable labels to cache, this action will end when the items are cached. It is optional to wait for caching to finish before this flow action is completed.
Addressables Download Content
Select which addressable labels asset bundles should be downloaded. Download all can also be set to download all asset bundle content to the latest version.
Custom Actions
Creating ActionTasks
Creating custom actions allows for almost endless expandability to the flow editor.
This is an example of a simple ActionTask which does not do anything.
namespace Game
{
[Category("Game")]
[Name("Example Flow Action")]
[Description("Custom description")]
public class ExampleFlowAction : ActionTask
{
protected override void OnExecute()
{
// Enter custom logic here.
EndAction();
}
}
}
Mandatory EndAction
Actions must call EndAction()
at some point, which marks this action as finished. If this is not called, the flow will get stuck on this action indefinitely.
Create custom drawers
Unfortunately, NodeCanvas inspector does not support Odin Inspector functionality. Which means you would have to create some drawers twice, once for Unity's inspector and another for Node Canvas inspector.
When you want to draw a library asset dropdown, use [FlowLibrary(typeof(LibraryType))]
on a string, which achieves the same result.
namespace Game
{
[Category("Game")]
[Name("Play music")]
[Description("Play music")]
public class PlayMusic : ActionTask
{
[FlowLibrary(typeof(MusicLibrary))]
public string Music;
public float FadeTime;
protected override void OnExecute()
{
if (Guid.TryParse(Music, out Guid guid))
{
Services.Get<AudioService>().PlayMusic(guid, FadeTime);
}
EndAction();
}
}
}
Read the Node Canvas (opens in a new tab) documentation on how to extend the functionality further.
Useful helpers
To get the parent node from within an ActionTask:
Node node = (ownerSystem as FSM).GetTaskParentElement(this) as Node;
Get the parent graph from any ActionTask or ConditionTask:
FSM fsm = (FSM)Graph.GetElementGraph(this);
Get all Tasks assigned to a node:
foreach (Task task in Graph.GetTasksInElement(node))
{
}
ActionList returned
Note that the tasks will also include the OnEnter, OnUpdate and OnExit ActionLists themselves.
So filter out the ActionList type if required.
Get all Tasks from a transition, which can be cast into your specific task if needed:
for (int i = 0; i < node.outConnections.Count; i++)
{
foreach (Task task in Graph.GetTasksInElement(node.outConnections[i]))
{
}
}
ConditionList returned
Note that in the case of multiple tasks on the transition, a ConditionList (which contains all the ConditionTasks) is also returned as one of the tasks. Filter it if required.