Variables
StoryFlow variables are the backbone of dynamic storytelling. They store state that persists throughout your story — tracking player choices, inventory, stats, and any other data your narrative depends on. This guide covers how to interact with them from Unreal Engine.
Variable Types
Every variable in a StoryFlow project carries a set of core properties:
- Id — A generated hash identifier (e.g.,
var_A3F8B21C). This is the string you pass to getter/setter functions. - Name — The human-readable display name (resolved via string table).
- Type — One of the
EStoryFlowVariableTypeenum values. - Value — The current value, stored as an
FStoryFlowVariant. - bIsArray — Whether this variable holds a single value or an array of values.
- EnumValues — For Enum-type variables, the list of valid option strings.
EStoryFlowVariableType Enum
The plugin defines the following variable types:
| Type | Category | Description |
|---|---|---|
Boolean | Core | True or false flags (quest completed, has item, etc.) |
Integer | Core | Whole numbers (gold, health, counts) |
Float | Core | Decimal numbers (percentages, multipliers) |
String | Core | Text values (names, messages, locations) |
Enum | Core | One value from a predefined set of named options |
Image | Asset reference | Reference to an image asset (used internally by the runtime) |
Audio | Asset reference | Reference to an audio asset (used internally by the runtime) |
Character | Asset reference | Reference to a character definition (used internally by the runtime) |
Core vs Asset Types
The five core types (Boolean, Integer, Float, String, Enum) are the ones you will interact with most often from Blueprints and C++. The asset reference types (Image, Audio, Character) are managed internally by the StoryFlow runtime to resolve media references during dialogue execution. You typically do not need to read or write asset-type variables directly.
FStoryFlowVariant
FStoryFlowVariant is the type-safe value container used throughout the plugin. It holds one value at a time along with its type tag, so you always know what kind of data you are working with.
Getter methods return a default if the variant holds a different type:
| Method | Return Type | Default |
|---|---|---|
GetBool() | bool | false |
GetInt() | int32 | 0 |
GetFloat() | float | 0.0f |
GetString() | FString | "" |
GetArray() | TArray<FStoryFlowVariant> | Empty array |
Factory methods create a variant from a typed value:
// Create variants from typed values
FStoryFlowVariant BoolVal = FStoryFlowVariant::FromBool(true);
FStoryFlowVariant IntVal = FStoryFlowVariant::FromInt(42);
FStoryFlowVariant FloatVal = FStoryFlowVariant::FromFloat(3.14f);
FStoryFlowVariant StringVal = FStoryFlowVariant::FromString(TEXT("Hello"));
// Read values back
bool bValue = BoolVal.GetBool(); // true
int32 iValue = IntVal.GetInt(); // 42
float fValue = FloatVal.GetFloat(); // 3.14
FString sValue = StringVal.GetString(); // "Hello"
// ToString() for display / logging
FString Display = IntVal.ToString(); // "42"
// Array support
TArray<FStoryFlowVariant> Items;
Items.Add(FStoryFlowVariant::FromInt(1));
Items.Add(FStoryFlowVariant::FromInt(2));
FStoryFlowVariant ArrayVal;
ArrayVal.SetArray(Items);
TArray<FStoryFlowVariant> Retrieved = ArrayVal.GetArray(); Local vs Global Scope
StoryFlow variables exist in one of two scopes, and the scope determines their lifetime and visibility:
| Property | Local Variables | Global Variables |
|---|---|---|
| Defined in | Per-script (.sfe file) | Project level (global-variables.json) |
| Lifetime | Copied fresh when a script starts executing | Shared across all components for the entire session |
| Visibility | Only accessible within that script | Accessible from any script, any component |
| Storage | UStoryFlowComponent instance | UStoryFlowSubsystem::GlobalVariables |
| Cross-component | No — each component has its own copy | Yes — changes in one component are visible to all others |
Scope Determines Behavior
The bGlobal parameter on every Get/Set function determines which scope to use. Passing the wrong value means you will read from or write to the wrong variable store. Local variables are per-component and reset on each script load, while global variables persist and are shared across every UStoryFlowComponent in the world via the UStoryFlowSubsystem.
// Reading a local variable (scoped to this component's current script)
bool bHasKey = StoryFlowComponent->GetBoolVariable("var_A3F8B21C", false);
// Reading a global variable (shared across all components)
int32 PlayerGold = StoryFlowComponent->GetIntVariable("var_7D2E9F01", true); Reading Variables
The UStoryFlowComponent exposes typed getter functions for reading variable values. All functions are available in both Blueprint and C++ under the category StoryFlow|Variables.
| Function | Parameters | Return Type |
|---|---|---|
GetBoolVariable | FString VariableId, bool bGlobal | bool |
GetIntVariable | FString VariableId, bool bGlobal | int32 |
GetFloatVariable | FString VariableId, bool bGlobal | float |
GetStringVariable | FString VariableId, bool bGlobal | FString |
GetEnumVariable | FString VariableId, bool bGlobal | FString |
Each function looks up the variable by its Id in either the local (component) or global (subsystem) store, then returns the value cast to the appropriate type. If the variable is not found, the type's default value is returned.
// C++ examples
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Local variables
bool bQuestComplete = SF->GetBoolVariable("var_A3F8B21C", false);
FString PlayerName = SF->GetStringVariable("var_B7C1D4E2", false);
// Global variables
int32 Gold = SF->GetIntVariable("var_7D2E9F01", true);
float Reputation = SF->GetFloatVariable("var_9E5F3A08", true);
FString Difficulty = SF->GetEnumVariable("var_C4D6E812", true); Finding Variable Ids
Variable Ids like var_A3F8B21C are generated by the StoryFlow Editor and exported in your JSON project file. You can find them in the script's variables array or in global-variables.json. Consider storing frequently-used Ids as constants or in a data table for easy reference.
Setting Variables
The component also exposes typed setter functions. Like the getters, these are available under the StoryFlow|Variables category in Blueprints.
| Function | Parameters | Returns |
|---|---|---|
SetBoolVariable | FString VariableId, bool Value, bool bGlobal | void |
SetIntVariable | FString VariableId, int32 Value, bool bGlobal | void |
SetFloatVariable | FString VariableId, float Value, bool bGlobal | void |
SetStringVariable | FString VariableId, FString Value, bool bGlobal | void |
SetEnumVariable | FString VariableId, FString Value, bool bGlobal | void |
Setting a variable updates the value in the appropriate scope and fires the OnVariableChanged delegate (see below). This means your game logic can react immediately to any change, whether triggered by a node in the StoryFlow graph or by your own Blueprint/C++ code.
// C++ examples
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Set a local boolean (e.g., after player picks up a key)
SF->SetBoolVariable("var_A3F8B21C", true, false);
// Set a global integer (e.g., award gold for completing a quest)
SF->SetIntVariable("var_7D2E9F01", 500, true);
// Set a global enum (e.g., change difficulty at runtime)
SF->SetEnumVariable("var_C4D6E812", TEXT("Hard"), true); OnVariableChanged Delegate
Every time a variable changes — whether from node execution inside the StoryFlow graph or from a direct Blueprint/C++ call — the OnVariableChanged delegate fires.
Signature:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
FOnVariableChanged,
FString, VariableId,
FStoryFlowVariant, NewValue,
bool, bIsGlobal
); Parameters:
- VariableId — The Id of the variable that changed.
- NewValue — The new value as an
FStoryFlowVariant. Use the typed getters (GetBool(),GetInt(), etc.) to extract the value. - bIsGlobal — Whether the change occurred in the global scope.
Binding in C++:
// In your actor's BeginPlay
UStoryFlowComponent* SF = FindComponentByClass<UStoryFlowComponent>();
SF->OnVariableChanged.AddDynamic(this, &AMyActor::HandleVariableChanged);
// Handler
void AMyActor::HandleVariableChanged(FString VariableId, FStoryFlowVariant NewValue, bool bIsGlobal)
{
if (VariableId == "var_7D2E9F01") // playerGold
{
int32 NewGold = NewValue.GetInt();
UpdateGoldUI(NewGold);
}
} Blueprint Binding
In Blueprints, select the StoryFlow Component, then in the Details panel find the OnVariableChanged event and click the + button to create a bound event node. The event node provides the VariableId, NewValue, and bIsGlobal as output pins you can use directly in your event graph.
Variable Interpolation in Dialogue
Dialogue text in StoryFlow can reference variables using the {varname} syntax. When the runtime builds the dialogue state, it automatically replaces these tokens with the current variable values.
// In the StoryFlow Editor dialogue node text:
"You have {playerGold} gold coins, {playerName}."
// At runtime, if playerGold = 500 and playerName = "Alice":
"You have 500 gold coins, Alice."
Interpolation is resolved automatically when the OnDialogueUpdated delegate fires. You do not need to perform any manual string replacement — the text in the dialogue state is already fully resolved.
Live Re-rendering on Variable Change
When a Set* node (setBool, setInt, setFloat, etc.) changes a variable and has no outgoing edge, the runtime returns to the current dialogue node and re-renders it with the updated variable values. This means the OnDialogueUpdated delegate fires again with the new interpolated text. Your UI simply needs to respond to OnDialogueUpdated as usual — the updated text arrives automatically.
Arrays
Variables can be arrays (bIsArray = true). An array variable holds an ordered list of FStoryFlowVariant values, all of the same type. Arrays are supported for all variable types: Bool, Int, Float, String, Image, Character, and Audio.
Array Operations
The StoryFlow node graph provides a full set of array manipulation nodes. These operations execute as part of the story flow and update the variable automatically:
| Operation | Description |
|---|---|
| Get / Set Array | Read or replace the entire array |
| Get / Set Element | Read or write a single element by index |
| Add | Append an element to the end of the array |
| Remove | Remove an element by value or index |
| Clear | Remove all elements from the array |
| Length | Get the number of elements in the array |
| Contains | Check if a value exists in the array (returns boolean) |
| FindIn | Get the index of a value (-1 if not found) |
| GetRandom | Retrieve a random element from the array |
The forEach loop node iterates over all elements in an array, executing the connected subgraph once per element. This is useful for processing inventories, applying effects to party members, or evaluating a list of quest objectives.
Arrays in C++ / Blueprint
From C++ or Blueprint, you can read an array variable's contents by getting the FStoryFlowVariant and calling GetArray(), which returns a TArray<FStoryFlowVariant>. To write an array, build the TArray and call SetArray() on the variant. Note that array operations from the node graph fire OnVariableChanged just like scalar changes.
Resetting Variables
The plugin provides functions to reset variables back to their initial values as defined in the StoryFlow project. This is useful for restarting a story, resetting a scene, or clearing state for a new game.
| Function | Class | What It Resets |
|---|---|---|
ResetVariables() | UStoryFlowComponent | Resets local variables on this component to their initial values from the script definition |
ResetGlobalVariables() | UStoryFlowSubsystem | Resets global variables to their project defaults |
ResetAllState() | UStoryFlowSubsystem | Resets global variables, characters, and once-only option tracking — a full session reset |
// Reset just this component's local variables
StoryFlowComponent->ResetVariables();
// Reset global variables across all components
UStoryFlowSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UStoryFlowSubsystem>();
Subsystem->ResetGlobalVariables();
// Full state reset (globals + characters + once-only options)
Subsystem->ResetAllState(); Reset Scope
ResetVariables() only affects the local variables of the specific UStoryFlowComponent you call it on. If you have multiple components in your world (e.g., multiple NPCs), each must be reset individually. For a full new-game reset, call ResetAllState() on the subsystem and then ResetVariables() on each active component.