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

Property
Type
Description

Debug Mode

bool

Enables verbose per-node logging via QuestLogger.

UI References

Property
Type
Description

Dialogue UI

DialogueUI

Required. The UI component that renders speaker text and player choices.

Camera Integration

Property
Type
Description

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

Event
Signature
Fired When

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

Event
Signature
Fired When

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:

  1. If a dialogue is already running, it ends it first.

  2. The player's movement is locked via ILockCharacter.Lock(true) (fetched from QuestManager.Instance.playerTransform).

  3. The currently active Cinemachine virtual camera is stored as previousCamera, along with its priority.

  4. nodeCache and outgoingEdgesCache dictionaries are built from all nodes and edges in the DialogueContainerSO for fast O(1) graph lookups.

  5. The Start Node is found and ProcessCurrentNode() begins execution.

  6. OnDialogueStarted fires.

When EndDialogue() is called (including from the End Node):

  1. Any active Timeline is stopped (final frame evaluated before stop).

  2. Any active FocusOnTarget coroutine is stopped and camera targets are restored.

  3. All speaker cameras that were activated during dialogue are reset to priority 1.

  4. The stored previousCamera is restored to its original priority.

  5. The Dialogue UI is hidden.

  6. Player movement is unlocked via ILockCharacter.Lock(false).

  7. Node/edge caches are cleared.

  8. OnDialogueEnded fires.


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.

Node Type
Behaviour

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:

Action
Behaviour

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:

  1. The PlayableDirector is assigned the asset and Play() is called.

  2. OnTimelineStarted fires.

  3. If Wait For Timeline Completion is enabled, a coroutine polls PlayableDirector.state until playback ends.

  4. OnTimelineCompleted fires 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:

Type
Storage
Accessed Via

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. DialogueManager is a DontDestroyOnLoad singleton. Duplicate instances are destroyed on Awake. Place it in your first bootstrapping scene.

  • DialogueUI is required. If dialogueUI is 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 no ILockCharacter is 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