Files
AppleHillsProduction/docs/dialogue_readme.md
2025-10-21 12:37:57 +02:00

18 KiB
Raw Blame History

Apple Hills Dialogue System

This document provides an overview of the dialogue system used in Apple Hills, intended primarily for designers (Damian) working with the dialogue creation tools.

Table of Contents

Overview

The Apple Hills dialogue system is a node-based dialogue management system that allows for interactive conversations with NPCs. The system currently supports linear, condition-guarded dialogue paths that can respond to various game conditions such as puzzle completion, item pickups, and item combinations. While the architecture was designed to facilitate branching dialogue in future extensions, the current implementation follows a linear progression through nodes.

Architecture at a Glance

  • Authoring Asset: RuntimeDialogueGraph (ScriptableObject) defines speaker name, entry node (entryNodeID), and all nodes (allNodes). Each RuntimeDialogueNode has a nodeType, nextNodeID, and content fields (dialogueContent for text/images and legacy dialogueLines).
  • Runtime Driver: DialogueComponent sits on an NPC/prop, subscribes to gameplay events (puzzle steps, item pickups/slots/combinations), and advances the graph. Exposes OnDialogueChanged, IsActive, IsCompleted, and helpers like StartDialogue(), HasAnyLines(), GetCurrentDialogueLine(), SetDialogueGraph(...).
  • Presentation: SpeechBubble renders text or images with instant/typewriter modes and manages a prompt icon when dialogue is available.
  • External Systems: PuzzleManager and ItemManager raise events that automatically progress WaitOn* nodes.

Quick Start (Code-First)

Minimal bootstrap in code

using Dialogue;
using UnityEngine;

public class DialogueBootstrap : MonoBehaviour
{
    [SerializeField] private DialogueComponent npcDialogue;
    [SerializeField] private RuntimeDialogueGraph graphAsset; // assign via Inspector

    private void Start()
    {
        // 1) Assign a graph at runtime (optional; can also be preassigned in Inspector)
        npcDialogue.SetDialogueGraph(graphAsset);

        // 2) Optionally subscribe to changes (for analytics/UI hooks)
        npcDialogue.OnDialogueChanged += line => Debug.Log($"[Dialogue] {npcDialogue.CurrentSpeakerName}: {line}");

        // 3) Start the dialogue flow programmatically (optional)
        npcDialogue.StartDialogue();

        // Speech bubble prompt visibility is managed automatically via HasAnyLines()
    }

    private void OnDestroy()
    {
        npcDialogue.OnDialogueChanged -= null; // Clean up if you subscribed with a lambda, store a delegate instead in real code
    }
}

Trigger an interaction by code (bypass Interactable)

The component usually advances when the player arrives and interacts (via Interactable). If you need to force-show the next line (e.g., a cutscene), you can invoke the same display pathway by starting the dialogue and letting the component manage advancement when it next receives input. For custom flows, prefer wiring your input to call StartDialogue() initially and rely on the built-in progression.

Switch graphs at runtime

// Swap to a new conversation (e.g., after quest completes)
npcDialogue.SetDialogueGraph(newGraph);
npcDialogue.StartDialogue();

Dialogue Structure

The dialogue system uses a graph-based structure with different types of nodes that control the flow of conversation. Each dialogue is represented as a graph containing multiple nodes connected through defined paths.

Dialogue Graph Example

Core Components

  1. RuntimeDialogueGraph: Container for dialogue nodes that make up a conversation

    • File: Assets/Scripts/Dialogue/RuntimeDialogueGraph.cs
    • Fields: entryNodeID, speakerName, allNodes
    • Helper: GetNodeByID(string id)
  2. DialogueComponent: Manages dialogue state and progression on an NPC/prop

    • File: Assets/Scripts/Dialogue/DialogueComponent.cs
    • Tracks current node/line; responds to puzzle/item events
    • Public: StartDialogue(), GetCurrentDialogueLine(), HasAnyLines(), SetDialogueGraph(RuntimeDialogueGraph)
    • Events/Props: OnDialogueChanged, IsActive, IsCompleted, CurrentSpeakerName
  3. SpeechBubble: Visual presentation of dialogue text/images and prompt

    • File: Assets/Scripts/Dialogue/SpeechBubble.cs
    • Public: Show(), Hide(), Toggle(), SetText(string), DisplayDialogueLine(string,bool), DisplayDialogueContent(DialogueContent,bool), UpdatePromptVisibility(bool), SetDisplayMode(TextDisplayMode), SkipTypewriter(), SetTypewriterSpeed(float)

QuickStart Guide

Setting up a dialogue interaction in your scene is straightforward:

1. Component Setup

  1. Place the Dialogue Component:

    • Add the DialogueComponent to any game object that has an Interactable component
    • The Interactable component handles player proximity and interaction triggers
    • Make sure the interactable is properly configured with appropriate interaction radius

    Dialogue Component Inspector

  2. Add DialogueCanvas:

    • Add the "DialogueCanvas" prefab from the project assets as a child of your object
    • Position the speech bubble appropriately above or near the interactable object
    • The speech bubble should be clearly visible but not obstruct important scene elements
    • You can adjust the scale and position to fit your specific character or object

    Speech Bubble Setup

  3. Assign Dialogue Graph:

    • Create a RuntimeDialogueGraph scriptable object (Right Click > Create > Dialogue Graph)
    • Set up your dialogue nodes in the graph (see Node Types for details)
    • Assign the created graph to the DialogueComponent on your object
    • Make sure to set the entry node ID in the dialogue graph

    Creating Dialogue Graph

2. Testing Your Dialogue

  1. Enter play mode and approach the interactable object

  2. When the component has any lines to serve, the speech bubble should display the prompt ("...")

  3. Interact with the object to advance through dialogue lines

  4. Test any conditional nodes by completing their requirements

  5. Verify that the dialogue progresses as expected

    Testing Dialogue Flow

3. Common Issues

  • No speech bubble appears: Check that the DialogueCanvas is properly added as a child and is active
  • Dialogue doesn't advance: Ensure the node connections (in/out) are properly set in the dialogue graph
  • Condition not triggering: Verify that the condition IDs (puzzle step, item, etc.) match exactly with your game systems

Node Types

The dialogue system supports several node types, each serving a specific purpose in the conversation flow:

1. Dialogue Node

Simple dialogue nodes display text to the player. They can contain multiple lines that are shown sequentially when the player interacts with the NPC.

Key features:

  • Multiple dialogue lines displayed in sequence
  • Optional looping through lines
  • Automatic progression to the next node when all lines are exhausted

Dialogue Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.Dialogue in RuntimeDialogueGraph.cs
  • Uses dialogueLines list to store sequential lines of text
  • The loopThroughLines boolean controls whether the dialogue returns to the first line after reaching the end

2. WaitOnPuzzleStep Node

This node pauses dialogue progression until a specific puzzle step has been completed by the player.

Key features:

  • Automatically advances when the specified puzzle step is completed
  • Displays dialogue while waiting for the condition to be met
  • Visual prompt appears when the condition is met, indicating available dialogue

WaitOnPuzzleStep Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.WaitOnPuzzleStep in RuntimeDialogueGraph.cs
  • Links to PuzzleManager.OnStepCompleted event through the puzzleStepID property
  • The DialogueComponent listens for puzzle completion events through OnAnyPuzzleStepCompleted method

3. WaitOnPickup Node

This node waits until the player has picked up a specific item before advancing the dialogue.

Key features:

  • Automatically advances when the player picks up the specified item
  • Shows dialogue while waiting for the item pickup
  • Visual prompt appears when the item is picked up, indicating available dialogue

WaitOnPickup Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.WaitOnPickup in RuntimeDialogueGraph.cs
  • Links to ItemManager.OnItemPickedUp event through the pickupItemID property
  • The DialogueComponent listens for item pickup events through OnAnyItemPickedUp method

4. WaitOnSlot Node

This node requires the player to place a specific item in a designated slot before the dialogue can progress.

Key features:

  • Supports different dialogue lines for different slot states:
    • Default lines when no item is slotted
    • Incorrect item lines when the wrong item is placed
    • Forbidden item lines when a specifically disallowed item is placed
  • Visual prompt appears when the correct item is slotted, indicating available dialogue

WaitOnSlot Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.WaitOnSlot in RuntimeDialogueGraph.cs
  • Uses multiple events from ItemManager including:
    • OnCorrectItemSlotted - Triggered when the matching slotItemID is placed
    • OnIncorrectItemSlotted - For displaying incorrect item dialogue
    • OnForbiddenItemSlotted - For displaying forbidden item dialogue
    • OnItemSlotCleared - For resetting to default dialogue

5. WaitOnCombination Node

This node waits for the player to create a specific item through the combination system.

Key features:

  • Automatically advances when the player creates the specified item through combination
  • Shows dialogue while waiting for the item combination
  • Visual prompt appears when the item is created, indicating available dialogue

WaitOnCombination Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.WaitOnCombination in RuntimeDialogueGraph.cs
  • Links to ItemManager.OnItemsCombined event through the combinationResultItemID property
  • The DialogueComponent listens for item combination events through OnAnyItemsCombined method

6. End Node

Terminates the dialogue sequence.

Key features:

  • Marks the dialogue as completed
  • No further interaction available until the dialogue is restarted

End Node Example

Implementation details:

  • Defined as RuntimeDialogueNodeType.End in RuntimeDialogueGraph.cs
  • When reached, sets the IsCompleted flag on the DialogueComponent
  • No next node connection is required for this node type

Dialogue Editor

The dialogue editor is a custom Unity tool that allows for visual creation and editing of dialogue graphs.

Dialogue Editor Interface

Key Editor Features

  • Visual Node Editing: Add and connect nodes in a visual graph
  • Node Type Selection: Choose from the six supported node types
  • Dialogue Text Entry: Add multiple lines of dialogue for each node
  • Condition Setup: Specify condition IDs for conditional nodes
  • Node Connections: Create the flow between dialogue nodes

Editor Workflow

  1. Create New Graph: Right-click in Project view and select Create > Dialogue Graph
  2. Open Editor: Double-click the created asset to open the dialogue editor
  3. Add Nodes: Right-click in the editor and select Add Node > [Node Type]
  4. Configure Nodes: Enter dialogue text and set conditions as needed
  5. Connect Nodes: Drag from output ports to input ports to create connections
  6. Set Entry Node: Mark one node as the entry point for the dialogue
  7. Save: Save your dialogue graph when finished

Designer Tips

  1. Node Organization

    • Start every dialogue graph with a standard Dialogue node as the entry point
    • End every dialogue path with an End node to properly terminate the conversation
    • Use conditional nodes strategically to create gameplay-driven dialogue experiences
  2. Dialogue Writing

    • Keep individual dialogue lines concise for better readability
    • Consider using the looping option for nodes when you want to repeat information
    • For WaitOnSlot nodes, write unique dialogue for incorrect/forbidden items to provide clear feedback
  3. Flow Control

    • Ensure all nodes (except End nodes) have a valid next node specified
    • Test dialogue paths to verify all conditions can be met during gameplay
    • Consider using multiple dialogue lines within a single node rather than creating separate nodes for sequential lines
  4. Best Practices

    • Name your nodes descriptively in the editor for easier management
    • Group related dialogue sequences into separate dialogue graphs
    • Use the speaker name field to clearly identify who is speaking

Technical Details

Public Events and APIs

The dialogue system exposes several events that can be used by other systems:

DialogueComponent

  • Events:

    • OnDialogueChanged: Triggered when the dialogue text changes
  • Properties:

    • IsActive: Indicates whether the dialogue is currently active
    • IsCompleted: Indicates whether the dialogue has reached an End node
    • CurrentSpeakerName: Returns the name of the current speaker
  • Public Methods:

    • StartDialogue(): Initiates the dialogue from the beginning
    • GetCurrentDialogueLine(): Retrieves the current dialogue line text
    • HasAnyLines(): Checks if the dialogue component has any lines available
    • SetDialogueGraph(RuntimeDialogueGraph): Sets the dialogue graph for the component

SpeechBubble

  • Public Methods:
    • Show(): Makes the speech bubble visible
    • Hide(): Hides the speech bubble
    • Toggle(): Toggles the visibility of the speech bubble
    • SetText(string): Sets the text displayed in the speech bubble
    • DisplayDialogueLine(string, bool): Displays a dialogue line and handles prompt visibility
    • UpdatePromptVisibility(bool): Updates the speech bubble to show a prompt or hide based on dialogue availability
    • SetDisplayMode(TextDisplayMode): Changes how text is displayed (instant or typewriter)
    • SkipTypewriter(): Immediately displays the full text, skipping the typewriter effect
    • SetTypewriterSpeed(float): Sets the speed of the typewriter effect

Integration with Other Systems

The dialogue system integrates with several other game systems:

  1. Puzzle System: Monitors puzzle completion events to advance WaitOnPuzzleStep nodes
  2. Item System: Tracks item pickups, combinations, and slot interactions to advance respective node types
  3. Interaction System: Responds to player interaction with the NPC to progress through dialogue lines

Technical Workflow

  1. Create a RuntimeDialogueGraph asset in the Unity editor
  2. Add nodes and connections using the dialogue editor
  3. Assign the graph to a DialogueComponent on an NPC GameObject
  4. Ensure a SpeechBubble component is available (as a child object or referenced)
  5. Set up any necessary puzzle steps, items, or slots that the dialogue will reference

Paths & Namespaces

  • Scripts: Assets/Scripts/Dialogue/
    • RuntimeDialogueGraph.cs
    • DialogueComponent.cs
    • SpeechBubble.cs
  • Editor tooling: Assets/Editor/Dialogue/
    • DialogueGraph.cs (graph editor)
    • DialogueNodes.cs (node types for editor)
    • DialogueGraphImporter.cs (asset importer)
  • Namespace: Dialogue

Troubleshooting / FAQ

  • The prompt (“…”) never shows:
    • Ensure a SpeechBubble exists under the same hierarchy and its serialized references are assigned.
    • Check DialogueComponent.HasAnyLines() returns true; verify your graphs entryNodeID and that nodes have content.
    • Confirm Interactable is present and wired if you rely on proximity to trigger dialogue.
  • Conditions dont trigger (puzzle/item):
    • Make sure PuzzleManager and ItemManager are present in the scene and raise the expected events.
    • Double-check IDs used in nodes (puzzleStepID, pickupItemID, slotItemID, combinationResultItemID).
  • Text doesnt animate:
    • Use SpeechBubble.SetDisplayMode(TextDisplayMode.Typewriter) and adjust with SetTypewriterSpeed().
    • Call SkipTypewriter() to reveal the full text instantly.
  • I want to switch to image-based dialogue:
    • Use RuntimeDialogueNode.dialogueContent and set DialogueContentType.Image entries instead of legacy dialogueLines.
  • Can I drive it purely by code?
    • Yes. Assign a RuntimeDialogueGraph via SetDialogueGraph(...), call StartDialogue(), and let DialogueComponent progress based on input or external events.

Change Log

  • v1.1: Added Table of Contents, Architecture at a Glance, code-first snippets, standardized inline code formatting, and appended Paths/Troubleshooting. Preserved all existing image references.
  • v1.0: Original overview and setup guide.