# DialogueTreeEditorWindow.cs: Explanation and Integration This document explains the `DialogueTreeEditorWindow.cs` script, a Unity Editor window for visually editing dialogue trees. It covers the script's functionality, its integration with the previously discussed dialogue system scripts (`DialogueManager.cs`, `DialogueNodeAuthoring.cs`, etc.), the purpose of each method, the GameObjects required, and how to use it in the Unity Editor. --- ## Overview of [[DialogueTreeEditorWindow.cs]] The `DialogueTreeEditorWindow.cs` script provides a **visual graph editor** in the Unity Editor for creating and editing dialogue trees. It allows developers to: - Create new dialogue nodes - Connect nodes via linear progression or branching choices - Edit node properties (e.g., character name, dialogue text, sprites, audio) - Save and load node layouts to/from JSON files - Automatically arrange nodes for better visualization This script builds on the dialogue system by providing a user-friendly interface to manage `DialogueNodeAuthoring` components, which define the dialogue structure. --- ## How [[DialogueTreeEditorWindow.cs]] Works ### General Functionality - **Graph View**: Uses Unity's `GraphView` API to create a node-based editor window where each node represents a `DialogueNodeAuthoring` component. - **Node Creation and Editing**: Allows adding new nodes, editing their properties (e.g., character name, dialogue text), and connecting them via ports (for linear progression or choices). - **Connections**: Supports linear connections (`linearNextNode`) and choice-based branching (`Choices` in `DialogueNodeAuthoring`). - **Layout Management**: Automatically arranges nodes (`AutoLayoutNodes`) and allows saving/loading custom layouts to JSON files. - **Integration**: Works directly with `DialogueNodeAuthoring` components attached to GameObjects, updating their properties in real-time. ### Integration with Other Scripts - **DialogueNodeAuthoring.cs**: The editor window directly manipulates `DialogueNodeAuthoring` components, which define dialogue nodes (e.g., character name, dialogue text, choices). Each node in the graph represents a `DialogueNodeAuthoring` component. - **DialogueManager.cs**: While not directly used at runtime, the editor creates dialogue structures that `DialogueManager` will later use to display dialogue in-game. - **NPCConversationManager.cs**: The dialogue trees edited in this window are part of the `dialogueRoot` GameObjects managed by `NPCConversationManager`, which can export/import them to/from JSON. - **NPCMemory.cs**: The editor allows setting memory keys/values for choices (`memoryKey`, `memoryValue`), which `NPCMemory` uses to track player choices. - **Environment.cs**: The editor ensures the selected `dialogueRoot` GameObject has an `Environment` component, as required by the dialogue system. --- ## Key Methods and Their Purpose ### Main Class: DialogueTreeEditorWindow - `OpenWindow()`: - **Purpose**: Static method to open the editor window. - **Details**: Accessible via the Unity Editor menu (`Window > Dialogue Tree Editor`). Creates or focuses the window and sets its title. - `OnEnable()`: - **Purpose**: Initializes the window when it’s opened. - **Details**: Calls `ConstructGraphView()` to set up the graph view and `AddToolbar()` to create the toolbar with controls. - `OnDisable()`: - **Purpose**: Cleans up when the window is closed. - **Details**: Clears the `rootVisualElement` to prevent memory leaks. - `ConstructGraphView()`: - **Purpose**: Sets up the `DialogueGraphView` (a custom `GraphView`). - **Details**: - Initializes the graph with zooming, dragging, and selection capabilities. - Adds a node creation request handler (right-click to add nodes if a `dialogueRoot` is selected). - Registers callbacks to save node positions (`GeometryChangedEvent`) and handle edge deletions (`graphViewChanged`). - `AddToolbar()`: - **Purpose**: Creates a toolbar with controls for selecting a dialogue root, adding nodes, and managing layouts. - **Details**: - **ObjectField**: Selects a `dialogueRoot` GameObject (must have an `Environment` component). - **Add Node Button**: Calls `AddNewNode()` to create a new dialogue node. - **Reset Layout Button**: Calls `ResetLayout()` to auto-arrange nodes. - **Save Layout Button**: Calls `SaveLayout()` to save node positions to a JSON file. - **Load Layout Button**: Calls `LoadSavedLayout()` to load saved node positions. - `AddNewNode()`: - **Purpose**: Creates a new dialogue node in the hierarchy and graph. - **Details**: - Prompts for a node name (defaults to "NewNode"). - Creates a new GameObject under the `dialogueRoot`, adds a `DialogueNodeAuthoring` component, and registers it for undo. - Adds a visual node to the graph via `CreateVisualNode()` and positions it. - `RefreshGraph()`: - **Purpose**: Updates the graph to reflect the current state of the `dialogueRoot`. - **Details**: - Clears existing nodes and edges. - Loads all `DialogueNodeAuthoring` components from the `dialogueRoot`. - Creates visual nodes and reconnects edges for linear and choice connections. - Applies saved layouts or auto-layout if none exists. - `ResetLayout()`: - **Purpose**: Resets the node layout to a default auto-arranged structure. - **Details**: Clears saved positions and calls `AutoLayoutNodes()` to rearrange nodes. - `AutoLayoutNodes(Dictionary<string, Node> nodeMap, Dictionary<string, DialogueNodeAuthoring> authoringMap, DialogueNodeAuthoring[] nodes)`: - **Purpose**: Automatically arranges nodes in the graph to avoid overlap. - **Details**: - Identifies the root node (a node with no incoming connections). - Uses `AssignPositions()` to recursively position nodes based on their connections (linear or choice-based). - Ensures nodes are spaced appropriately (`NODE_WIDTH`, `NODE_HEIGHT`, `HORIZONTAL_SPACING`, `VERTICAL_SPACING`). - `FindNextAvailableY(float x, float desiredY, Dictionary<float, List<float>> occupiedYPositions)`: - **Purpose**: Helper method to find a non-overlapping Y position for a node at a given X coordinate. - **Details**: Adjusts the Y position to avoid overlap with other nodes, ensuring proper spacing. - `AssignPositions(DialogueNodeAuthoring node, Dictionary<string, DialogueNodeAuthoring> nodeMap, Dictionary<string, Vector2> positionMap, Dictionary<float, List<float>> occupiedYPositions, HashSet<string> visited, float x, float y)`: - **Purpose**: Recursively positions nodes in the graph. - **Details**: - Positions the current node at `(x, y)` after adjusting `y` to avoid overlap. - Recursively positions the `linearNextNode` and choice nodes at the next X level. - Adjusts Y positions for choice nodes to fan out vertically (`CHOICE_VERTICAL_OFFSET`, `VERTICAL_SPACING`). - `SaveLayout()`: - **Purpose**: Saves the current node positions to a JSON file. - **Details**: - Saves positions to `Assets/DialogueLayouts/[dialogueRootName]_Layout.json`. - Serializes positions using `SerializableNodePositions`. - `LoadSavedLayout()`: - **Purpose**: Loads saved node positions from a JSON file. - **Details**: - Loads from `Assets/DialogueLayouts/[dialogueRootName]_Layout.json`. - Applies saved positions to nodes in the graph. - `CreateVisualNode(DialogueNodeAuthoring authoringNode, Dictionary<string, Node> nodeMap)`: - **Purpose**: Creates a visual node in the graph for a `DialogueNodeAuthoring` component. - **Details**: - Sets up the node’s UI with fields for editing properties (e.g., `characterName`, `dialogueText`, `characterSprite`). - Adds input/output ports for connections (linear and choices). - Supports adding new choices (`AddChoiceUI`), renaming nodes, and selecting the GameObject in the hierarchy. - Updates the `DialogueNodeAuthoring` component in real-time with `Undo` support. - `AddChoiceUI(Node node, DialogueNodeAuthoring authoringNode, int choiceIndex)`: - **Purpose**: Adds UI for a choice to a visual node. - **Details**: - Creates fields for `choiceText`, `memoryKey`, and `memoryValue`. - Adds an output port for connecting the choice to another node. - Updates the `DialogueNodeAuthoring.Choices` list with `Undo` support. ### Nested Classes #### DialogueGraphView - **Purpose**: A custom `GraphView` subclass for the dialogue editor. - **Details**: Initializes with basic manipulators (dragging, zooming, selection). #### EdgeConnectorListener - **Purpose**: Handles choice connections between nodes. - **Methods**: - `OnDropOutsidePort(Edge edge, Vector2 position)`: Connects a choice to a node if dropped near its input port. - `OnDrop(GraphView graphView, Edge edge)`: Connects a choice to a node when dropped on its input port, updating `choice.nextNode`. #### LinearEdgeConnectorListener - **Purpose**: Handles linear connections between nodes. - **Methods**: - `OnDropOutsidePort(Edge edge, Vector2 position)`: Connects a linear next node if dropped near an input port. - `OnDrop(GraphView graphView, Edge edge)`: Connects a linear next node, updating `linearNextNode`. --- ## How It Works with Other Scripts - **DialogueNodeAuthoring.cs**: - The editor window directly modifies `DialogueNodeAuthoring` components attached to GameObjects. - Each visual node represents a `DialogueNodeAuthoring` instance, allowing editing of its properties (e.g., `characterName`, `dialogueText`, `Choices`). - Connections (linear or choice-based) update the `linearNextNode` and `Choices` fields. - **DialogueManager.cs**: - The dialogue trees created/edited in this window are used by `DialogueManager` at runtime to load and display dialogue. - The editor ensures the dialogue structure is valid for `DialogueManager` to process. - **NPCConversationManager.cs**: - The `dialogueRoot` GameObject selected in the editor is the same one managed by `NPCConversationManager`. - `NPCConversationManager` can export the edited dialogue trees to JSON, preserving the structure created in the editor. - **NPCMemory.cs**: - The editor allows setting `memoryKey` and `memoryValue` for choices, which `NPCMemory` uses to track player decisions and influence future conversations. - **Environment.cs**: - The editor enforces that the `dialogueRoot` GameObject has an `Environment` component, aligning with the dialogue system’s requirements. --- ## GameObjects Needed - **Dialogue Root GameObject**: - Must have an `Environment` component (enforced by the editor). - Children: GameObjects with `DialogueNodeAuthoring` components (representing dialogue nodes). - Typically part of an NPC’s hierarchy, as used by `NPCConversationManager`. - **No Additional Runtime GameObjects**: - This script is an **Editor-only tool** and does not require GameObjects at runtime beyond what the dialogue system already needs (e.g., `dialogueRoot` for `NPCConversationManager`). --- ## How to Use [[DialogueTreeEditorWindow.cs]] in the Unity Editor ### Setup 1. **Ensure Prerequisites**: - The dialogue system scripts (`DialogueManager.cs`, `DialogueNodeAuthoring.cs`, `Environment.cs`, `NPCConversationManager.cs`, `NPCMemory.cs`) must be in your project. - Create an NPC GameObject with `NPCConversationManager` and a `dialogueRoot` child GameObject. - Add an `Environment` component to the `dialogueRoot` GameObject. 2. **Open the Editor Window**: - In the Unity Editor, go to `Window > Dialogue Tree Editor`. - This opens the `Dialogue Tree Editor` window. ### Using the Editor 1. **Select a Dialogue Root**: - In the toolbar at the top of the window, use the `ObjectField` labeled "Dialogue Root" to select your `dialogueRoot` GameObject. - The GameObject must have an `Environment` component, or the selection will be rejected. - Once selected, the graph will populate with existing nodes (if any). 2. **Add Nodes**: - Click the `Add Node` button in the toolbar (or right-click in the graph view). - Enter a name for the new node (defaults to "NewNode"). - A new GameObject with a `DialogueNodeAuthoring` component will be created under the `dialogueRoot`, and a visual node will appear in the graph. 3. **Edit Node Properties**: - Each node in the graph displays fields for editing: - `Character`, `Sprite`, `Emotion`, `Text`, `Audio`, `Animation`, `Char Panel Color`, `Dialogue Panel Color`, `Text Color` - `Player Name`, `Player Sprite`, `Player Emotion`, `Is Player Speaking` - Changes are saved to the `DialogueNodeAuthoring` component with `Undo` support. 4. **Add Choices**: - Click the `Add Choice` button on a node to add a choice. - Edit the `Choice` text, `Memory Key`, and `Memory Value`. - Connect the choice to another node by dragging from the yellow output port to another node’s cyan input port. 5. **Connect Nodes**: - **Linear Connections**: Drag from the green `Linear Next` port to another node’s input port to set `linearNextNode`. - **Choice Connections**: Drag from a choice’s yellow output port to another node’s input port to set `choice.nextNode`. - Deleting an edge (select and press Delete) clears the connection in the `DialogueNodeAuthoring` component. 6. **Manage Layout**: - **Reset Layout**: Click `Reset Layout` to auto-arrange nodes. - **Save Layout**: Click `Save Layout` to save node positions to a JSON file (`Assets/DialogueLayouts/[dialogueRootName]_Layout.json`). - **Load Layout**: Click `Load Layout` to load saved positions. 7. **Additional Features**: - **Rename Node**: Click the `Rename` button on a node to rename it. - **Select Object**: Click the `Select Object` button to select the node’s GameObject in the hierarchy. ### Post-Editing - The dialogue tree created/edited in the window is ready to be used by `NPCConversationManager` and `DialogueManager` in-game. - You can export the dialogue to JSON using `NPCConversationManager`’s export functionality for runtime loading. ![[Dialogue Tree Editor Network.png]] ![[Dialogue Tree Editor Node.png]] --- ## Summary - **Purpose**: `DialogueTreeEditorWindow.cs` provides a visual editor for creating and managing dialogue trees in the Unity Editor. - **Integration**: Works with `DialogueNodeAuthoring` to define dialogue nodes, integrates with `NPCConversationManager` for runtime use, and supports `NPCMemory` for choice-based memory. - **Key Features**: Node creation, property editing, connections (linear/choices), auto-layout, save/load layouts. - **Usage**: Open via `Window > Dialogue Tree Editor`, select a `dialogueRoot`, and edit the dialogue tree visually. This script enhances the dialogue system by providing a user-friendly interface for developers to design complex dialogue structures, which are then used by the runtime scripts to deliver an interactive experience in a 2D game.