Skip to main content

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 GDScript.

Variable Types

Every variable in a StoryFlow project carries a set of core properties:

  • Id - A generated hash identifier (e.g., var_A3F8B21C). Used internally by the runtime.
  • Name - The human-readable display name. This is the string you pass to getter/setter functions from GDScript.
  • Type - One of the StoryFlowTypes.VariableType enum values.
  • Value - The current value, stored as a StoryFlowVariant.
  • is_array - Whether this variable holds a single value or an array of values.
  • enum_values - For Enum-type variables, the list of valid option strings.

VariableType Enum

The plugin defines the following variable types in StoryFlowTypes.VariableType:

Type Category Description
NONE Default No type / uninitialized. A StoryFlowVariant with this type returns false from is_valid().
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 GDScript. 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.

StoryFlowVariant

StoryFlowVariant is the type-safe value container used throughout the plugin. It extends RefCounted and 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
get_bool(default) bool false
get_int(default) int 0
get_float(default) float 0.0
get_string(default) String ""
get_array() Array Empty array

Factory methods create a variant from a typed value:

GDScript
# Create variants from typed values
var bool_val := StoryFlowVariant.from_bool(true)
var int_val := StoryFlowVariant.from_int(42)
var float_val := StoryFlowVariant.from_float(3.14)
var string_val := StoryFlowVariant.from_string("Hello")
var enum_val := StoryFlowVariant.from_enum("Hard")

# Read values back
var b: bool = bool_val.get_bool()       # true
var i: int = int_val.get_int()           # 42
var f: float = float_val.get_float()     # 3.14
var s: String = string_val.get_string()  # "Hello"

# to_display_string() for display / logging
var display: String = int_val.to_display_string()  # "42"

# is_valid() checks if the variant has been assigned a type
var valid: bool = int_val.is_valid()  # true

# duplicate_variant() creates a deep copy
var copy := int_val.duplicate_variant()

# Array support
var items: Array = []
items.append(StoryFlowVariant.from_int(1))
items.append(StoryFlowVariant.from_int(2))
var array_val := StoryFlowVariant.from_array(items)
var retrieved: Array = array_val.get_array()

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 StoryFlowComponent instance StoryFlowRuntime autoload
Cross-component No - each component has its own copy Yes - changes in one component are visible to all others

Automatic Scope Resolution

Unlike the Unreal Engine plugin, the Godot plugin does not require a is_global parameter on getter/setter functions. When you call get_bool_variable("hasKey"), the component looks up the variable by display name in the local scope first. If no match is found locally, it falls back to the global scope automatically. This means you simply pass the variable name and let the component resolve the scope for you.

GDScript
# The component resolves scope automatically: local first, then global
var has_key: bool = storyflow.get_bool_variable("hasKey")
var player_gold: int = storyflow.get_int_variable("playerGold")

Reading Variables

The StoryFlowComponent exposes typed getter functions for reading variable values by their display name.

Function Parameter Return Type
get_bool_variable name: String bool
get_int_variable name: String int
get_float_variable name: String float
get_string_variable name: String String
get_enum_variable name: String String

Each function looks up the variable by its display name, checking the local scope first and then falling back to global. If the variable is not found, the type's default value is returned.

GDScript
@onready var storyflow: StoryFlowComponent = %StoryFlowComponent

# Read variables by display name (scope resolved automatically)
var quest_complete: bool = storyflow.get_bool_variable("questComplete")
var player_name: String = storyflow.get_string_variable("playerName")
var gold: int = storyflow.get_int_variable("playerGold")
var reputation: float = storyflow.get_float_variable("reputation")
var difficulty: String = storyflow.get_enum_variable("difficulty")

Variable Names

Variable names are the human-readable display names you assign in the StoryFlow Editor (e.g., playerGold, questComplete). You pass these names directly to getter/setter functions - no need to look up internal IDs.

Setting Variables

The component also exposes typed setter functions. Like the getters, these resolve scope automatically.

Function Parameters Returns
set_bool_variable name: String, value: bool void
set_int_variable name: String, value: int void
set_float_variable name: String, value: float void
set_string_variable name: String, value: String void
set_enum_variable name: String, value: String void

Setting a variable updates the value in the appropriate scope and emits the variable_changed signal (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 GDScript code.

GDScript
@onready var storyflow: StoryFlowComponent = %StoryFlowComponent

# Set a boolean (e.g., after player picks up a key)
storyflow.set_bool_variable("hasKey", true)

# Set an integer (e.g., award gold for completing a quest)
storyflow.set_int_variable("playerGold", 500)

# Set an enum (e.g., change difficulty at runtime)
storyflow.set_enum_variable("difficulty", "Hard")

variable_changed Signal

Every time a variable changes - whether from node execution inside the StoryFlow graph or from a direct GDScript call - the variable_changed signal is emitted.

Signal signature:

GDScript
signal variable_changed(info: StoryFlowVariableChangeInfo)

StoryFlowVariableChangeInfo properties:

  • id (String) - The internal variable identifier (hash key).
  • name (String) - The human-readable display name of the variable.
  • value (StoryFlowVariant) - The new value after the change.
  • is_global (bool) - Whether the change occurred in the global scope.

Connecting to the signal:

GDScript
@onready var storyflow: StoryFlowComponent = %StoryFlowComponent

func _ready() -> void:
    storyflow.variable_changed.connect(_on_variable_changed)

func _on_variable_changed(info: StoryFlowVariableChangeInfo) -> void:
    if info.name == "playerGold":
        var new_gold: int = info.value.get_int()
        update_gold_ui(new_gold)

    # You can also check by scope:
    if info.is_global:
        print("Global variable '%s' changed" % info.name)
    else:
        print("Local variable '%s' changed" % info.name)

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.

Code
// 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 dialogue_updated signal 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 dialogue_updated signal fires again with the new interpolated text. Your UI simply needs to respond to dialogue_updated as usual - the updated text arrives automatically.

Arrays

Variables can be arrays (is_array = true). An array variable holds an ordered list of StoryFlowVariant 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 GDScript

From GDScript, you can read an array variable's contents by getting the StoryFlowVariant and calling get_array(), which returns an Array of StoryFlowVariant objects. To write an array, build the Array and call set_array() on the variant, or use StoryFlowVariant.from_array(). Note that array operations from the node graph emit variable_changed 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
reset_variables() StoryFlowComponent Resets local variables on this component to their initial values from the script definition
reset_global_variables() StoryFlowManager Resets global variables to their project defaults
reset_all_state() StoryFlowManager Resets global variables, runtime characters, and once-only option tracking - a full session reset
GDScript
# Reset just this component's local variables
storyflow.reset_variables()

# Reset global variables across all components
var manager = get_node("/root/StoryFlowRuntime")
manager.reset_global_variables()

# Full state reset (globals + characters + once-only options)
manager.reset_all_state()

Reset Scope

reset_variables() only affects the local variables of the specific StoryFlowComponent you call it on. If you have multiple components in your scene (e.g., multiple NPCs), each must be reset individually. For a full new-game reset, call reset_all_state() on the manager and then reset_variables() on each active component.

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