Hello and welcome to lesson 5 of the articy:draft Importer for Unity tutorial series.

Recap lesson 4

In the last lesson we added functionality to the UI buttons in our scene, so that we can now traverse through the entire linear test dialogue and close the dialogue UI at the end.

Recap lesson 4

This lesson

In this lesson we will start setting up branching functionality by instantiating buttons for the branches the player encounters at any part of the dialogue.

Lesson 5 content

Setting up branching functionality

Let’s take a look at what we are working with in articy:draft. Branch Test is a simple dialogue, branching out to two and to three choices, which will help us to evaluate the button layout later in this and coming lessons.

Branching test dialogue in articy:draft

We add Branch Test as the target of the ArticyReference of NPC 2, then we take a quick look at how the dialogue looks in a play through of the scene.

Adding reference target for NPC2

It is displayed, however we do not have any branching, at the branching points the first option gets selected automatically.

For branching dialogue 1st option gets auto selected currently

To set up the functionality for branching, we first have to break some of the functionality we have created so far. The current solution works fine for linear dialogue, but to be able to react to a changing number of dialogue options, we need to update our code.

Having said that, we are going to remove everything in the DialogueManager script that has to do with both dialogue and end dialogue buttons. As well as the ContinueDialogue method.

[SerializeField]
Button dialogueButton;
[SerializeField]
Button endDialoguebutton;

void Start()
{
       	dialogueButton.onClick.AddListener(ContinueDialogue);
	endDialogueButton.onClick.AddListener(CloseDialogueBox);
}

public void ContinueDialogue()
{
       	flowPlayer.Play(); 
}

public void StartDialogue(IArticyObject aObject)
{
       	dialogueButton.gameObject.SetActive(DialogueActive);
}   	

public void CloseDialogueBox()
{
       	endDialoguebutton.gameObject.SetActive(DialogueActive);
}   	

public void OnBranchesUpdated(IList<Branch> aBranches)
{
       
       	if (dialogueIsFinished)
       	{
            		dialogueButton.gameObject.SetActive(false);
            		endDialoguebutton.gameObject.SetActive(true);
        }
}

Then we declare two new variables and open them to the editor via the SerializeField attribute: one of type RectTransform called branchLayoutPanel and one of type GameObject called branchPrefab.

[SerializeField]
RectTransform branchLayoutPanel;
[SerializeField]
GameObject branchPrefab;

In Unity we start by setting the dialogueBranch and dialogueBranchClose objects back to active and then prefab them. This is crucial, as we are going to base our instantiation of new buttons on these prefabs.

Prefab dialogueBranch and dialogueBranchClose objects

Now we drag the dialogueBranch prefab over to the Branch Prefab reference field. Again, very important that we use the prefab here!

Fill reference with dialogueBranch prefab

The Branch Layout Panel reference field we fill with the Dialogue Branches object. We touched upon this object in the last video: it is responsible for the button layout and positioning, so that the buttons we are going to instantiate know where they have to appear.

Fill reference with Dialogue Branches object

You are very free in the design of your dialogue UI. You can have the dialogue options displayed next to each other, below each other, or in the form of a dialogue wheel; for the approach we are aiming for it is just important to create the two button prefabs and set up a layout rule, to position the instantiated buttons in the desired way.

Now we need to get some coding done. Go to the OnBranchesUpdated method in the DialogueManager script. We change the second if-statement to now check if the dialogue is not finished, by adding an exclamation mark. In case there is more text coming after the node we are currently on, we want to create a button for each branch following.

Inside the if-statement we create another foreach loop to go through all branch objects of the list aBranches. In this loop we are creating a new branch button. We declare a variable btn of type GameObject and assign the value of Instantiate(branchPrefab) to it. With the instantiate method we can also set the parent with a handy overload, which will be branchLayoutPanel.

if (!dialogIsFinished)
{
	foreach (var branch in aBranches)
        {
             	GameObject btn = Instantiate(branchPrefab, branchLayoutPanel);
	}
}

There a few small steps left, then we can do a test if the button creation works. We create a new method and call it ClearAllBranches. In this method we go through all child objects of branchLayoutPanel with a foreach loop and destroy them. We add ClearAllBranches to OnBranchesUpdated, removing all old branches each time OnBranchesUpdated is called.

private void ClearAllBranches()
{
       	foreach (Transform child in branchLayoutPanel)
        {
        	Destroy(child.gameObject);
        }
}

public void OnBranchesUpdated(IList aBranches)
{
       ClearAllBranches();
}

Recap lesson 5

Now we can run a test in Unity. The buttons are back to being without function for now, but we have achieved the goal for today’s lesson: We have started to implement branching functionality for the dialogue navigation buttons. For the linear test dialogue, where there is one branch following the current node, one button is instantiated.

Linear test dialogue

For the branch test dialogue, where two branches come after the current node, we have two buttons properly instantiated and positioned in the dialogue UI. Great stuff!

Branching test dialogue

Recap lesson 5

Next lesson

In the next lesson we will add text and functionality to the navigational buttons. For a linear dialogue it is fine to just have a prompt to click along, but with two or more choices, I think it would improve the game immensely if the player could actually see what fate they are choosing. Don’t you agree?

What's next?

See you there!

Current state of C# scripts we have worked on this lesson:

DialogueManager.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Articy.Unity;
using Articy.Unity.Interfaces;
using Articy.UnityImporterTutorial;
using System;

public class DialogueManager : MonoBehaviour, IArticyFlowPlayerCallbacks
{
    [Header("UI")]
    // Reference to Dialog UI
    [SerializeField]
    GameObject dialogueWidget;
    // Reference to dialogue text
    [SerializeField]
    Text dialogueText;
    // Reference to speaker
    [SerializeField]
    Text dialogueSpeaker;
    // Reference to button layout
    [SerializeField]
    RectTransform branchLayoutPanel;
    // Reference to navigation button prefab
    [SerializeField]
    GameObject branchPrefab;


    // To check if we are currently showing the dialog ui interface
    public bool DialogueActive { get; set; }

    private ArticyFlowPlayer flowPlayer;

    void Start()
    {
        flowPlayer = GetComponent<ArticyFlowPlayer>();        
    }

    public void StartDialogue(IArticyObject aObject)
    {
        DialogueActive = true;
        dialogueWidget.SetActive(DialogueActive);
        flowPlayer.StartOn = aObject;               
    }

    public void CloseDialogueBox()
    {
        DialogueActive = false;
        dialogueWidget.SetActive(DialogueActive);
        // Completely process current object before we end dialogue
        flowPlayer.FinishCurrentPausedObject();
    }

    public void OnFlowPlayerPaused(IFlowObject aObject)
    {
        //Clear data
        dialogueText.text = string.Empty;
        dialogueSpeaker.text = string.Empty;
  
        // If we paused on an object that has a "Text" property fetch this text and present it      
        var objectWithText = aObject as IObjectWithText;
        if (objectWithText != null)
        {
            dialogueText.text = objectWithText.Text;
        }

        // If the object has a "Speaker" property try to fetch the speaker
        var objectWithSpeaker = aObject as IObjectWithSpeaker;
        if (objectWithSpeaker != null)
        {
            // If the object has a "Speaker" property, fetch the reference
            // and ensure it is really set to an "Entity" object to get its "DisplayName"
            var speakerEntity = objectWithSpeaker.Speaker as Entity;
            if (speakerEntity != null)
            {
                dialogueSpeaker.text = speakerEntity.DisplayName;
            }
        }
    }

    // Called every time the flow player encounters multiple branches,
    // or is paused on a node and wants to tell us how to continue 
    public void OnBranchesUpdated(IList<Branch> aBranches)
    {
        // Destroy buttons from previous use, will create new ones here
        ClearAllBranches();

        // Check if any branch leads to a DialogueFragment target
        // If so, the dialogue is not yet finished
        bool dialogueIsFinished = true;
        foreach (var branch in aBranches)
        {
            if (branch.Target is IDialogueFragment)
            {
                dialogueIsFinished = false;
            }
        }

        if (!dialogueIsFinished)
        {
            // If we have branches, create a button for each of them
            foreach (var branch in aBranches)
            {
                // Instantiate a button in the Dialogue UI
                GameObject btn = Instantiate(branchPrefab, branchLayoutPanel);
            }
        }
    }
 
    // Delete buttons from previous branches
    void ClearAllBranches()
    {
        foreach (Transform child in branchLayoutPanel)
        {
            Destroy(child.gameObject);
        }
    }
}

GO TO LESSON 6

Don’t have articy:draft 3 yet? Get the free version now!
Get articy:draft 3 FREE
*No payment information required

Follow us on Twitter, Facebook and LinkedIn to keep yourself up to date and informed.