Skip to main content

StoryFlow Component

The StoryFlow Component is the core MonoBehaviour that drives dialogue execution in your Unity project. It manages the runtime, processes node graphs, and fires events your UI can respond to.

Overview

StoryFlowComponent is a MonoBehaviour that you attach to any GameObject in your scene - an NPC, a trigger volume, a game manager, or any other object that needs to run dialogue. It is marked with [DisallowMultipleComponent], so each GameObject can have at most one instance.

Internally, the component manages a StoryFlowExecutionContext that walks the node graph, handles the call stack, processes script transitions, and produces dialogue state. You do not interact with the execution context directly. The component exposes a clean C# API for starting dialogue, selecting options, reading variables, and listening to events.

One Component Per Dialogue

Each StoryFlowComponent runs one dialogue at a time. If you need multiple concurrent dialogues (for example, an NPC conversation and a tutorial prompt), use separate components on separate GameObjects. All components share global state through the StoryFlowManager singleton.

Adding the Component

There are two ways to add the component to a GameObject:

  1. In the Inspector, click Add Component and search for "StoryFlow Component" (listed under StoryFlow).
  2. In code, call AddComponent<StoryFlowComponent>() on any GameObject.
C#
using StoryFlow;

// Add the component to an NPC at runtime
var storyFlow = npcObject.AddComponent<StoryFlowComponent>();
storyFlow.Script = elderScript; // assign a StoryFlowScriptAsset reference

// Or reference it from a serialized field
[SerializeField] private StoryFlowComponent storyFlowComponent;

Configuration Properties

All configuration properties are exposed in the Inspector. They are also accessible from C# scripts as public fields.

General Settings

Script StoryFlowScriptAsset

Reference to the script asset to run when StartDialogue() is called with no arguments. Drag a StoryFlowScriptAsset from your project into this field. If left empty, the project's startup script is used as a fallback.

LanguageCode string default: "en"

The language code used for string table lookup. Determines which localized text is displayed in dialogue. Currently, the StoryFlow Editor only supports English ("en"). Multi-language localization is planned for a future release.

DialogueUI StoryFlowDialogueUI optional

Optional reference to a dialogue UI handler. If set, the component automatically binds to the UI when dialogue starts, calling its OnDialogueStarted, HandleDialogueUpdated, OnDialogueEnded, OnVariableChanged, and OnBackgroundImageChanged methods. If left empty, a built-in fallback UI is auto-created at runtime for quick prototyping. To manage your own UI entirely via C# events, subscribe to the component's events directly.

Audio Settings

These properties control how dialogue audio is played. They appear under the Audio header in the Inspector.

StopAudioOnDialogueEnd bool default: true

When enabled, any playing dialogue audio is stopped when the dialogue session ends. Disable this if you want audio to continue playing after the conversation finishes (for example, ambient music triggered by dialogue).

DialogueAudioMixerGroup AudioMixerGroup

Assigns all dialogue audio to a specific mixer group. Use this to control volume through your game's audio mixer (for example, a "Dialogue" or "Voice" group).

DialogueVolumeMultiplier float default: 1.0, range: 0-2

Volume multiplier applied to all dialogue audio. Clamped between 0 and 2. Useful for per-component volume adjustments without changing the mixer group settings.

Events

The component provides two categories of events: C# events (Action-based, for code subscribers) and UnityEvents (Inspector-assignable, for designer workflows). Both fire at the same time.

C# Events (Action-based):

Event Signature Description
OnDialogueStarted Action Fired when dialogue execution begins. Use this to show your dialogue UI, disable player movement, or enter a dialogue camera mode.
OnDialogueUpdated Action<StoryFlowDialogueState> The primary UI update event. Fired every time the dialogue state changes - new text, new options, character change, or variable interpolation update.
OnDialogueEnded Action Fired when dialogue execution completes (reaching an End node or calling StopDialogue). Use this to hide your UI and re-enable player input.
OnVariableChanged Action<StoryFlowVariable, bool> Fired when a variable is modified during execution. The second parameter indicates whether the variable is global (true) or local (false).
OnScriptStarted Action<string> Fired when execution enters a new script via a runScript node. Parameter is the script path.
OnScriptEnded Action<string> Fired when execution returns from a script. Parameter is the script path that just finished.
OnError Action<string> Fired when the runtime encounters an error (missing script, invalid node connection, stack overflow). Use for logging or error feedback during development.
OnBackgroundImageChanged Action<Sprite> Fired when a setBackgroundImage node executes. Parameter is the new background sprite.
OnAudioPlayRequested Action<AudioClip, bool> Fired when a playAudio node executes. Parameters are the audio clip and whether it should loop. Use this if you want to handle audio playback yourself.

UnityEvents (Inspector-assignable):

Event Type Description
OnDialogueStartedEvent UnityEvent Inspector-assignable version of OnDialogueStarted. Wire up callbacks in the Inspector without writing code.
OnDialogueUpdatedEvent UnityEvent<StoryFlowDialogueState> Inspector-assignable version of OnDialogueUpdated. Receives the full dialogue state.
OnDialogueEndedEvent UnityEvent Inspector-assignable version of OnDialogueEnded.

OnDialogueUpdated is Your Main Hook

In most projects, OnDialogueUpdated is the only event you need to build a complete dialogue UI. It fires whenever the dialogue state changes and provides the full StoryFlowDialogueState including text, character, options, images, and audio. See Displaying Dialogue for details on the state class.

Subscribing in C#:

C#
using StoryFlow;
using StoryFlow.Data;

public class NPCDialogue : MonoBehaviour
{
    [SerializeField] private StoryFlowComponent storyFlow;

    private void OnEnable()
    {
        storyFlow.OnDialogueStarted += HandleDialogueStarted;
        storyFlow.OnDialogueUpdated += HandleDialogueUpdated;
        storyFlow.OnDialogueEnded += HandleDialogueEnded;
    }

    private void OnDisable()
    {
        storyFlow.OnDialogueStarted -= HandleDialogueStarted;
        storyFlow.OnDialogueUpdated -= HandleDialogueUpdated;
        storyFlow.OnDialogueEnded -= HandleDialogueEnded;
    }

    private void HandleDialogueStarted()
    {
        // Show your dialogue UI
    }

    private void HandleDialogueUpdated(StoryFlowDialogueState state)
    {
        // Update your UI with the new dialogue state
    }

    private void HandleDialogueEnded()
    {
        // Hide your dialogue UI, re-enable player input
    }
}

Control Methods

These public methods control the dialogue flow. Call them from your input handlers, UI buttons, or game logic scripts.

Method Parameters Description
StartDialogue() None Begins dialogue using the configured Script asset. Falls back to the project's startup script if Script is not assigned.
StartDialogue(string) string scriptPath Begins dialogue with the specified script path, overriding the component's Script property.
StartDialogue(StoryFlowScriptAsset) StoryFlowScriptAsset script Begins dialogue with a direct asset reference. Useful for avoiding path lookups.
SelectOption(string) string optionId Selects a dialogue option by its ID. The ID comes from StoryFlowOption.Id in the current dialogue state.
AdvanceDialogue() None Advances the dialogue when the current node has no options. Equivalent to the player clicking "continue".
StopDialogue() None Immediately stops dialogue execution and fires OnDialogueEnded.
PauseDialogue() None Pauses dialogue execution. The dialogue state is preserved until resumed.
ResumeDialogue() None Resumes a paused dialogue from exactly where it left off.
PauseExecution() None Pauses node execution after the current node completes. The next node is held until ResumeExecution() is called.
ResumeExecution() None Resumes execution from a PauseExecution() hold.
PauseExecutionFor(float) float seconds Pauses execution for the given duration, then resumes automatically. Returns a Coroutine you can track or stop.
InputChanged(string, string) string optionId, string value Submits a typed input value change for an input option. Stores the value, re-interpolates dialogue text, broadcasts OnDialogueUpdated, and optionally follows an "on change" edge.
InputChanged(string, StoryFlowVariant) string optionId, StoryFlowVariant value Typed overload of InputChanged that accepts a StoryFlowVariant directly.
C#
// Player interacts with NPC
public void OnInteract()
{
    if (!storyFlowComponent.IsDialogueActive())
    {
        storyFlowComponent.StartDialogue();
    }
}

// Player presses "Continue" key
public void OnContinuePressed()
{
    if (storyFlowComponent.IsDialogueActive()
        && storyFlowComponent.IsWaitingForInput())
    {
        storyFlowComponent.AdvanceDialogue();
    }
}

// UI button calls this when the player picks an option
public void OnOptionSelected(string optionId)
{
    storyFlowComponent.SelectOption(optionId);
}

State Access

These methods let you query the current state of the dialogue without modifying it. They are safe to call from UI update logic, animation controllers, or any read-only context.

Method Return Type Description
GetCurrentDialogue() StoryFlowDialogueState Returns the current dialogue state. May return null if no dialogue is active.
IsDialogueActive() bool Returns true if a dialogue is currently running. Useful for input gating and UI visibility checks.
IsWaitingForInput() bool Returns true if the dialogue is waiting for the player to select an option or advance.
IsPaused() bool Returns true if the dialogue is currently paused via PauseDialogue().
GetProject() StoryFlowProjectAsset Returns the effective project asset from StoryFlowManager.Instance.Project.

Variable Access

These methods let you read and write StoryFlow variables from game code. Each variable type has its own getter and setter pair. All lookups are by display name (the name shown in the StoryFlow Editor), not by internal ID.

Method Parameters Return Type
GetBoolVariable string name, bool global = false bool
SetBoolVariable string name, bool value, bool global = false void
GetIntVariable string name, bool global = false int
SetIntVariable string name, int value, bool global = false void
GetFloatVariable string name, bool global = false float
SetFloatVariable string name, float value, bool global = false void
GetStringVariable string name, bool global = false string
SetStringVariable string name, string value, bool global = false void
GetEnumVariable string name, bool global = false string
SetEnumVariable string name, string value, bool global = false void
GetCharacterVariable string charPath, string varName StoryFlowVariant
SetCharacterVariable string charPath, string varName, StoryFlowVariant value void
ResetVariables None void

The global Parameter

The global parameter (default false) determines search scope. When false, the getter searches local script variables first, then falls back to global. When true, only global variables are searched. If a variable is defined as global in the StoryFlow Editor, pass global: true to target it directly.

C#
// Check if the player has completed a quest (global variable)
bool questDone = storyFlowComponent.GetBoolVariable("mainQuestCompleted", global: true);

// Give the player gold (local script variable)
int currentGold = storyFlowComponent.GetIntVariable("gold");
storyFlowComponent.SetIntVariable("gold", currentGold + 100);

// Set a character-specific variable
storyFlowComponent.SetCharacterVariable(
    "characters/elder",
    "trustLevel",
    StoryFlowVariant.Int(5)
);

// Reset all local variables to their default values
storyFlowComponent.ResetVariables();

ResetVariables Scope

ResetVariables() only resets local script variables to their default values. Global variables are not affected. To reset global variables, call StoryFlowManager.Instance.ResetGlobalVariables().

Lifecycle

The component follows a straightforward lifecycle tied to Unity's MonoBehaviour callbacks:

  • StartDialogue() - When you call StartDialogue(), the component retrieves a reference to StoryFlowManager.Instance, initializes its execution context with the shared state (global variables, runtime characters, once-only option tracking), and auto-binds to the DialogueUI if one is assigned. It subscribes the UI to OnDialogueStarted, OnDialogueUpdated, OnDialogueEnded, OnVariableChanged, and OnBackgroundImageChanged. It then walks the node graph, fires events, and waits for player input. You can pause, resume, or stop at any time.
  • OnDisable - If a dialogue is active, it is stopped cleanly, firing OnDialogueEnded.
  • OnDestroy - Stops any active dialogue and nullifies all C# event subscribers to prevent memory leaks from dangling references.
C#
// Simplified lifecycle overview
private void OnDisable()
{
    if (isDialogueActive)
        StopDialogue();
}

private void OnDestroy()
{
    if (isDialogueActive)
        StopDialogue();

    // Clear all C# event subscribers to prevent memory leaks
    OnDialogueStarted = null;
    OnDialogueUpdated = null;
    OnDialogueEnded = null;
    OnVariableChanged = null;
    OnError = null;
    OnAudioPlayRequested = null;
    OnBackgroundImageChanged = null;
    OnScriptStarted = null;
    OnScriptEnded = null;
}

Relationship with StoryFlowManager

StoryFlowManager is a singleton MonoBehaviour that persists across scene loads via DontDestroyOnLoad. It acts as the central authority for shared state, while each StoryFlowComponent operates as an independent dialogue runner. The manager auto-creates itself at runtime when first needed - you do not need to manually add it to your scene. It automatically discovers the project asset in your project.

What the manager handles:

  • Global Variables - A single global variable store shared by all components. When one component's dialogue sets a global variable, every other component sees the updated value immediately.
  • Runtime Characters - Deep copies of character data loaded from the project asset. Character variables modified during gameplay are shared across all components.
  • Once-Only Options - Tracks which "show once" dialogue options have already been selected. This tracking persists across different components and script files within the same session.
  • Project Asset - Holds the imported StoryFlow project (StoryFlowProjectAsset) with all scripts, characters, and resolved media assets.
  • Save/Load - Provides SaveToSlot() and LoadFromSlot() methods that serialize and restore all shared state.

What each component manages independently:

  • Local Variables - Each component has its own local variable scope for the currently executing script.
  • Execution State - Call stack, current node position, and flow state are per-component.
  • Audio Playback - Each component creates and manages its own AudioSource on demand.
  • Events - C# events and UnityEvents are fired per-component, so each GameObject's UI only receives updates for its own dialogue.

Multiple NPCs, Shared World

This architecture means you can have dozens of NPCs running independent dialogues while sharing the same world state. A merchant NPC can check a global mainQuestCompleted variable that was set by a quest-giver NPC's dialogue, and both share the same character relationship data - all without any manual synchronization.

Need Help?

Join our Discord community to ask questions, share your projects, report bugs, and get support from the team and other users.

Join Discord