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.
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.
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.
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.
It is displayed, however we do not have any branching, at the branching points the first option gets selected automatically.
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.
Now we drag the dialogueBranch prefab over to the Branch Prefab reference field. Again, very important that we use the prefab here!
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.
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(IListaBranches) { 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.
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!
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?
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); } } }
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, or visit our articy Reddit to keep yourself up to date and informed.