Audio
StoryFlow supports audio playback tied to dialogue nodes, standalone audio triggers, and audio variables. This guide covers how audio assets are handled, configured, and played back in the Unity plugin.
How Audio Works
Dialogue nodes in the StoryFlow Editor can have audio attached. When the runtime reaches a dialogue node with audio assigned, the StoryFlowComponent automatically plays the AudioClip through an AudioSource component that is created on demand on the same GameObject.
The dialogue state exposes audio as StoryFlowDialogueState.Audio (AudioClip). This value is null when no audio is assigned to the dialogue node.
// Access audio from the current dialogue state
void OnDialogueUpdated(StoryFlowDialogueState state)
{
// state.Audio is an AudioClip - may be null if no audio is assigned
if (state.Audio != null)
{
// Audio is available for this dialogue node.
// The plugin handles playback automatically via AudioSource,
// but you can also access the clip directly for custom handling.
}
} Fresh Entry vs Return
Audio only plays on a fresh entry to a dialogue node - that is, when the runtime arrives at the node by following an edge from another node. When a Set* node (such as setBool, setInt, etc.) has no outgoing edge and returns to the dialogue for re-rendering, audio does not re-trigger. This prevents audio from restarting every time a variable changes during an active dialogue.
Audio Settings
The StoryFlowComponent exposes several audio-related properties in the Inspector under the Audio header. These settings apply globally to all dialogue audio played by the component.
| Setting | Type | Default | Description |
|---|---|---|---|
StopAudioOnDialogueEnd | bool | true | When enabled, stops all playing dialogue audio when the dialogue session ends (End node reached or StopDialogue() called). |
DialogueAudioMixerGroup | AudioMixerGroup | null | Assigns all dialogue audio to a specific mixer group. Use this to create a dedicated "Dialogue" volume slider separate from music, SFX, and other audio categories. |
DialogueVolumeMultiplier | float | 1.0 | Volume scaling multiplier (range 0-2) applied to all dialogue audio. Stacks with the mixer group volume. |
// Configure audio settings in C#
StoryFlowComponent sf = GetComponent<StoryFlowComponent>();
// Stop audio when dialogue ends (default behavior)
sf.StopAudioOnDialogueEnd = true;
// Assign a mixer group for volume control
sf.DialogueAudioMixerGroup = dialogueMixerGroup;
// Set volume to 80%
sf.DialogueVolumeMultiplier = 0.8f; Audio Format
Unity imports audio files natively as AudioClip assets. The plugin resolves audio asset keys to AudioClip references during import, so they are ready for playback at runtime.
Recommended Format: WAV
WAV is the recommended format for dialogue audio. Unity supports WAV, MP3, OGG, and other common formats natively. WAV files provide the best compatibility and avoid any codec-related issues. Unity handles audio compression internally based on your import settings, so you get optimal file sizes regardless of the source format.
Looping and Reset
Each dialogue node in the StoryFlow Editor has two audio-related settings that control playback behavior:
- AudioLoop (
bool) - When enabled, the dialogue's audio loops continuously for as long as the dialogue is active. The plugin sets theAudioSource.loopproperty to achieve this. - AudioReset (
bool) - When enabled and the dialogue has no audio assigned, any previously playing dialogue audio is stopped. This gives you explicit control over when audio should be cut - for example, a narrative dialogue node that should play in silence after a voiced line.
These properties are available on the StoryFlowDialogueState as AudioLoop and AudioReset if you need to inspect them from your UI code.
Two additional audio properties on the dialogue state control auto-advance behavior:
- AudioAdvanceOnEnd (
bool) - When enabled, the dialogue automatically advances when the audio clip finishes playing. The component polls theAudioSourceeach frame and callsAdvanceDialogue()when playback ends. Note: this is automatically disabled whenAudioLoopistrue, since looping audio never finishes. - AudioAllowSkip (
bool) - When enabled alongsideAudioAdvanceOnEnd, the player can manually advance past the audio-gated wait. When disabled, the dialogue remains locked until the audio finishes. This is automaticallyfalsewhenAudioAdvanceOnEndisfalse. UseSetAudioAdvanceState(bool waiting, bool allowSkip)to control this programmatically.
// Simplified internal logic for dialogue audio playback
void ProcessDialogueAudio(StoryFlowDialogueState state, bool isFreshEntry)
{
if (isFreshEntry && state.Audio != null)
{
// Fresh entry with audio - play it
PlayDialogueAudio(state.Audio, state.AudioLoop);
// If AudioAdvanceOnEnd is set, the dialogue will auto-advance
// when the audio clip finishes playing
if (state.AudioAdvanceOnEnd)
SetAudioAdvanceState(true, state.AudioAllowSkip);
}
else if (isFreshEntry && state.Audio == null && state.AudioReset)
{
// Fresh entry, no audio, reset enabled - stop any playing audio
StopDialogueAudio();
}
// Returning from a Set* node: do nothing with audio
} Custom Audio Handling
For standalone audio triggers (via the playAudio node in the graph), the plugin broadcasts the OnAudioPlayRequested event rather than playing audio automatically. Subscribe to this event to handle playback yourself:
void Start()
{
var sf = GetComponent<StoryFlowComponent>();
sf.OnAudioPlayRequested += HandleAudioPlayRequested;
}
void OnDestroy()
{
var sf = GetComponent<StoryFlowComponent>();
if (sf != null)
sf.OnAudioPlayRequested -= HandleAudioPlayRequested;
}
void HandleAudioPlayRequested(AudioClip clip, bool loop)
{
// Handle audio playback yourself
// Useful for ambient sounds, music, stingers, etc.
// Route through your own audio manager if needed
myAudioSource.clip = clip;
myAudioSource.loop = loop;
myAudioSource.Play();
} PlayAudio is a broadcast, not automatic playback
Unlike dialogue-attached audio which the plugin plays automatically, the playAudio node only broadcasts an event. Your game code is responsible for handling playback. This gives you full control - for example, routing music through a separate audio manager or layering ambient sounds.
Programmatic Control
The StoryFlowComponent provides public methods for direct audio control:
| Method | Parameters | Description |
|---|---|---|
PlayDialogueAudio | AudioClip clip, bool loop | Plays the given clip through the component's AudioSource. Stops any currently playing dialogue audio first. Creates the AudioSource on demand if needed. |
StopDialogueAudio | none | Stops the dialogue AudioSource if it is currently playing and clears the clip reference. |
IsDialogueAudioPlaying | none | Returns true if the dialogue AudioSource is currently playing. |
SetAudioAdvanceState | bool waiting, bool allowSkip | Controls the audio-advance gate. When waiting is true, the component polls for audio completion and auto-advances when done. allowSkip determines whether the player can advance manually before audio finishes. |
StoryFlowComponent sf = GetComponent<StoryFlowComponent>();
// Play a clip manually
sf.PlayDialogueAudio(myClip, loop: false);
// Check if audio is playing
if (sf.IsDialogueAudioPlaying())
{
Debug.Log("Dialogue audio is active.");
}
// Stop dialogue audio
sf.StopDialogueAudio();
The AudioSource is created lazily on the component's GameObject the first time audio is played. It is configured as 2D audio (spatialBlend = 0) with playOnAwake disabled. The mixer group and volume multiplier from the component settings are applied automatically each time PlayDialogueAudio is called.