Dialogue Manager
Overview
DialogueManager is the central runtime engine of the Dialogue System. It takes a DialogueContainerSO asset, traverses the node graph from start to end, and coordinates every system involved in the conversation — the dialogue UI, Cinemachine cameras, Unity Timeline, Malbers character actions, quest operations, audio playback, and player input gating.
The component is a persistent singleton (DontDestroyOnLoad) and should appear once in your first scene. All other dialogue-related scripts communicate with it through DialogueManager.Instance.

Inspector Properties
Configuration
Debug Mode
bool
Enables verbose per-node logging via QuestLogger.
UI References
Dialogue UI
DialogueUI
Required. The UI component that renders speaker text and player choices.
Camera Integration
Cinemachine Brain
CinemachineBrain
The scene's Cinemachine Brain. Auto-found at Start if not assigned.
Default Camera Blend Time
float
Default blend duration (seconds) for camera transitions. Default: 1.0.
Events
OnDialogueStarted
UnityEvent<DialogueContainerSO>
Dialogue begins.
OnDialogueLine
UnityEvent<string>
A SimpleDialogue or Choice node displays text. Passes the raw dialogue string.
OnDialogueEnded
UnityEvent
Dialogue ends (End Node reached, or EndDialogue() called).
OnChoiceMade
UnityEvent<int>
Player selects a choice. Passes the zero-based choice index.
Timeline Events
OnTimelineStarted
UnityEvent<PlayableAsset>
A Timeline begins playing.
OnTimelineCompleted
UnityEvent
A Timeline finishes playing naturally.
OnTimelineSkipped
UnityEvent
A Timeline is skipped by the player.
How It Works
Startup & Teardown
When StartDialogue(DialogueContainerSO) is called:
If a dialogue is already running, it ends it first.
The player's movement is locked via
ILockCharacter.Lock(true)(fetched fromQuestManager.Instance.playerTransform).The currently active Cinemachine virtual camera is stored as
previousCamera, along with its priority.nodeCacheandoutgoingEdgesCachedictionaries are built from all nodes and edges in theDialogueContainerSOfor fast O(1) graph lookups.The Start Node is found and
ProcessCurrentNode()begins execution.OnDialogueStartedfires.
When EndDialogue() is called (including from the End Node):
Any active Timeline is stopped (final frame evaluated before stop).
Any active FocusOnTarget coroutine is stopped and camera targets are restored.
All speaker cameras that were activated during dialogue are reset to priority
1.The stored
previousCamerais restored to its original priority.The Dialogue UI is hidden.
Player movement is unlocked via
ILockCharacter.Lock(false).Node/edge caches are cleared.
OnDialogueEndedfires.
Node Processing
ProcessCurrentNode() reads currentNode.type (a string) and dispatches to a type-specific handler. Execution is always sequential — the graph moves to the next node via AdvanceToNextNode() or, for branching nodes, directly by GUID lookup.
StartNode
Immediately advances to the next node. The entry point for the dialogue.
SimpleDialogueNode / DialogueNode
Displays text and speaker in the UI. Optionally focuses the camera on the speaker's assigned virtual camera. Waits for ContinueDialogue().
ChoiceDialogueNode
Displays text and a list of choices. Waits for MakeChoice(int). Routes to the connected node based on port name matching ("Choice 1", "Choice 2", etc.).
EndNode
Calls EndDialogue().
TrueFalseNode
Evaluates a Malbers Conditions2 block against a target (node-specified → Player → DialogueManager as fallback). Routes via the "True" or "False" output port.
RandomNode
Picks a random outgoing edge uniformly and jumps to that node.
QuestNode
Calls QuestManager.StartQuest, CompleteQuest, FailQuest, or AbandonQuest for the assigned quest. Advances automatically.
MalbersEventNode
Invokes the assigned MEvent ScriptableObject. Advances automatically.
MalbersCharacterActionNode
Activates a State or Mode on an MAnimal component (resolved via TransformVar). If Wait For Action is enabled, a coroutine polls ActiveStateID or ActiveMode every frame until the action exits, then advances.
Reactions2Node
Applies an MReactions2Var to a target transform. Advances automatically (fire-and-forget).
WaitNode
Hides the Dialogue UI, waits for waitDuration seconds via coroutine, then restores and advances.
AudioNode
Plays, Stops, or Pauses an AudioClip on a target object's AudioSource (or one added dynamically). Advances automatically.
CinemachineDialogueNode
Executes a camera action (see below). Optionally plays a Unity Timeline. May wait for camera completion or timeline completion before advancing.
ModalWindowNode
Hides the Dialogue UI, instantiates a UI prefab, waits for ContinueDialogue(), fades out and destroys the prefab (0.3s fade), then advances.
Camera System
The CinemachineDialogueNode supports six Camera Actions:
SwitchCamera
Boosts the target virtual camera's priority to 100.
FocusOnSpeaker
Boosts the target DialogueSpeaker's assigned virtual camera to priority 100.
BlendToTarget
Directs the camera toward a custom TransformVar target.
FocusOnTarget
Modifies the main gameplay camera's Follow and LookAt targets to point at a TransformVar. Stores original targets and restores them afterwards. Supports blend-wait, pause-at-target, and return-to-previous-camera — all configurable per node.
ResetToGameplay
Immediately resets all speaker cameras and restores the pre-dialogue camera.
PlayTimeline
Signals that a Timeline should play (handled by the Timeline pipeline).
All virtual cameras activated during a dialogue conversation are tracked in activatedSpeakerCameras and reset to priority 1 on EndDialogue().
If Wait For Camera Completion is enabled on a node, the CameraCompletionHandlerFactory creates a type-specific handler (e.g. dolly cart, orbit) that is polled each frame until the camera reports it has finished its movement. An optional timeout prevents indefinite blocking.
Timeline Support
When a CinemachineDialogueNode has both a TimelineAsset and PlayableDirector assigned:
The
PlayableDirectoris assigned the asset andPlay()is called.OnTimelineStartedfires.If Wait For Timeline Completion is enabled, a coroutine polls
PlayableDirector.stateuntil playback ends.OnTimelineCompletedfires on natural completion.
Skip: If allowTimelineSkip is enabled on the node, calling ContinueDialogue() during playback will jump the director to its final frame, evaluate it, stop, and fire OnTimelineSkipped before advancing.
Dialogue Variables
DialogueManager maintains three persistent runtime dictionaries across conversations:
bool
dialogueFlags
SetFlag / GetFlag
string
dialogueStrings
SetString / GetString
int
dialogueIntegers
SetInt / GetInt
These variables are used by the custom Malbers Conditions2 conditions (C2_DialogueFlag, C2_DialogueInt, C2_DialogueString) to drive TrueFalseNode branching decisions.
The save system reads these via GetAllFlags(), GetAllStrings(), and GetAllIntegers(), and restores them on load via RestoreVariables().
Public API
Dialogue Control
Dialogue Variables
Save / Load Integration
Notes
One instance only.
DialogueManageris a DontDestroyOnLoad singleton. Duplicate instances are destroyed onAwake. Place it in your first bootstrapping scene.DialogueUI is required. If
dialogueUIis null at Start, an error is logged and dialogue calls will silently fail.Player locking. The player's movement is locked at the start of any dialogue and unlocked at the end. The player object must implement
ILockCharacter(Malbers Animal Controller). If noILockCharacteris found, locking is silently skipped.Cinemachine Brain. If not assigned in the inspector, the manager will attempt
FindFirstObjectByType<CinemachineBrain>()at Start. For scenes that have a brain but load it dynamically, assign it manually.Choice routing uses port names, not list order. Choice edges are matched by the port name
"Choice 1","Choice 2", etc. — not by their serialization index. This makes re-ordering choices in the graph editor safe.TrueFalse routing uses port names. Edges are matched by
"True"and"False"port names, ensuring correct routing regardless of edge serialization order.Unconnected non-terminal nodes. If a non-End node has no outgoing connections, a warning is logged and
EndDialogue()is called automatically.Dialogue variables persist. Variable dictionaries (flags, strings, integers) are not cleared between separate dialogue conversations — only by
ClearAllVariables()or a load operation. Design around this if using them for per-conversation state.
Last updated