Hello and welcome to lesson 3 of the articy:draft Importer for Unreal tutorial series.
Recap lesson 2
In the previous lesson we began setting up the dialogue system for the Unreal project. We are now able to display the first dialogue line plus the speaker name in the custom dialogue UI after interacting with an NPC.
In this lesson, we will add a button to the dialogue UI to be able to traverse through the entire Linear test dialogue.
Branch Button widget
First things first. Before we can add a button, we need to create a button widget object. I go to the Widgets folder and create a widget blueprint under the bullet point User Interface. As the root widget I select User Widget. I call it WPB for widget blueprint, underscore, Branch Button.
Why do we have to create a separate object and don’t just add a button to the WBP_Dialogue widget? At the moment this would suffice, this is correct. But when we get to branching – which is the goal we are working towards – we will need different amounts of buttons. We will use this separate element to dynamically create the number of buttons needed at any point throughout the dialogue.
The widget itself consists of a canvas panel with a childed button (1).
The button gets sized to fit nicely with the dialogue box (2), and I change the tints for hover and clicked to make the states more obvious (3). The button needs to be exposed as a variable, but that should be the default for this element type anyway (4).
Then I put a default text on the button (1, 2), which needs to be exposed as a variable as well (3).
Adding functionality to Branch Button
That’s all for the design part, now we add an On Clicked event to the button object and continue in the graph.
What do we want to accomplish on a button click? We want to continue the conversation, so we need to tell the Flow Player, which is currently pausing, to get going again. To get access to the Flow Player component, we start by getting the game mode and casting it to the Demo Game Mode. From this we can get the articy Flow Player and use it as the target for the Play function.
Now we need to create a place for the button to appear. We will do that in the Dialogue widget blueprint.
We can go with either a Wrap Box or a Scroll Box, depending on how many branches we have in our project at any one time and how much space we want to reserve for displaying them. For this tutorial project I set myself a limit of never having more than three options, so I will go with a Wrap Box as three options will fit nicely beneath the dialogue box without the need of scroll bars.
I give it a proper name (1) and expose it as a variable (2). Then size it to fit the branch button (3) and position it below the dialogue box (4).
Now we need to set up a way to actually add the Branch Button to the Dialogue widget. This will happen in the Demo Game Mode blueprint.
For the one button we need for our linear dialogue, we could simply add the button widget creation to the Play Dialogue function, but as we will have to deal with more buttons in a short while, let’s set it up in a way we can easily expand for branching dialogue later. Select the articy Flow Player component and add an On Branches Updated event to the graph.
We start with a Sequence node and add a For Each Loop to connection 1. You will see in a bit why we leave 0 open for now. The loop takes in the array of all available branches provided by the event.
For the linear dialogue we have at the moment checking the next element with an if statement would also work, but we already want to prepare for the coming steps in which the loop will become necessary. We get the target of the current element and cast it to an Articy Object With Text. Next we create the Branch Button widget and add it as a child to the Wrapbox of the Dialogue widget.
Getting to Wrapbox Branches is a bit of effort, as we need to go from the Player HUD to the Dialogue Widget and from there to the wrap box.
And we will need to access it a couple of times more in this lesson. So let’s make our lives a bit easier and the blueprint a bit more readable. I am going to cut this at this position and paste it in our Begin Play event. Here I add another pin to the sequence and promote Wrapbox Branches to a variable. Now we can use the variable whenever we need to access the wrap box object.
Let’s test our solution. We can now traverse through the dialogue. But the behavior is a bit strange as buttons are stacking up while we go through the dialogue and we have no button do end the dialogue.
The stacking buttons we can fix very quickly. You remember that we left the 0 pin of the sequence open? We add a Clear Children node here, targeting the wrap box.
Already looks better, right?
Now, let’s add a way to end the dialogue. For that we need another button and a way to determine if the dialogue came to an end. To save some time, we can duplicate the Branch Button widget and rename the copy to Close Button.
In the Designer we also have to change the button name (1) and the text we display (2). To make it easier to recognize that we are dealing with a different button, I will also change the text color to red (3). As we always want to display the same text for the Close button we can also remove the variable checkmark for the Button text (4).
The On Clicked Event we also only need to change slightly. Instead of calling the Play function for the Flow Player, here we call the End Dialogue function.
When does a dialogue end?
We have our button to end a dialogue, now we need to determine when the current dialogue is actually over. This we do back in the Demo Game Mode in the On Branches Updated event.
Let’s quickly recap what we have so far in regards to the implementation of articy data: When the player character interacts with an NPC that has an articy reference, like our NPC 1 with the reference to the Linear Test dialogue, the articy Flow Player gets started on the first node of the reference. It traverses through the flow until it encounters a node type that is set to Pause On. Which for our linear test dialogue is right away, as the referenced object is a Dialogue node, which we set as a pauseable type.
Now the On Player Paused event evaluates what to do with the node we currently pause on. It is a Dialogue, so we immediately start up the Flow Player again (1). The Flow Player now submerges into the node and accesses its inner content. The first node it comes across is a Dialogue Fragment, so the Flow Player pauses again.
The On Player Paused event runs again and, as we are now dealing with a Dialogue Fragment, displays its text and speaker information to the screen (2).
Simultaneously the On Branches Updated event checks the available following branches and creates a Branch Button widget for each of those. As we are in a linear dialogue at the moment, this always leads to one button for the next element.
Technically that already happened with the first node, but as the Flow Player got restarted immediately we don’t see that on screen.
The last dialogue line does not have a button. That is because there is no following branch. On Branches Updated does not run through the loop again as there are no more array elements to check. And exactly this we will utilize for the Close Button. We add another pin to the Sequence and add a Branch to this connection. In the condition for this branch we check if the Wrap Box has any children, meaning if at this point any buttons are displayed. If the condition returns false, that means there are no buttons present, we create the Close Button widget and add it as a child to wrap box.
The functionality for a linear dialogue is complete. We can traverse through the dialogue and end it properly by closing the dialogue UI. Very nice, we are getting there!
A bit more about casts
Before we come to the end of this lesson I want to go a bit more into detail about the casts we did and why it can make a difference to what we cast depending on how the project is set up.
In On Branches Updated we used a cast to an Articy Object With Text to determine if a Branch Button is added. And it worked fine for the project as it is. But watch what happens if I go into articy and connect the linear and branch test dialogues and export to Unreal.
The dialogue does not end at the expected spot but just continues right on. At the spot where On Branches Updated could not detect a following branch earlier it now can, as the flow moves to the second Dialogue node. Which is an Articy Object With Text.
We could of course remove the connection in articy again, but for demonstration purposes we can also change the cast to fix the issue. Articy Object With Text is too broad for us here. In this articy project Dialogue nodes are just meant as containers for the actual dialogue lines. And every dialogue is created as a separate node in articy. So we know a dialogue is supposed to be over if there is no following Dialogue Fragment.
Because of that we can make the cast narrower, we can cast to a Dialogue Fragment. You should, however, never use the generic type ArticyDialogueFragment. This in Unreal is implemented as empty as possible and only contains very general properties. The better option is to use a generated variant based on the articy project. This variant inherits from the generic variant, but also includes more project specific properties.
It is named after the technical name of your articy project plus Dialogue Fragment. You can find the technical name of your project (1) when you select the topmost entry in the Navigator (2) and press F8 or select Open Properties from the right-click context menu.
In this case I need to do a cast to UEImporterTutorialDialogueFragment. Even if you don’t use any of the more specific properties at the moment, it has no downside to using the generated variant over the generic one when casting to a Dialogue Fragment.
If we now compile and play the level the dialogue ends as expected, even though the dialogue nodes are still connected in articy. That is because when the Flow Player arrives at the following Dialogue node the cast will fail and no additional button gets created. Which, in the next step leads to the creation of the end dialogue button.
Overall it comes down to how your project is set up and what kind of behavior you expect. But if you encounter any issues like the example before it is always a good approach to check how your articy and Unreal projects are set up and what node types you selected the Flow Player to pause on. That could influence if you have to make certain casts broader or narrower.
Recap lesson 3
We have arrived at the end of this lesson. This time around we updated our dialogue system to a point where now we can traverse through linear dialogues and end them. If you are just looking to display linear dialogue, like cut-scenes, you can already use the current solution as a basis.
Up next in lesson 4
In the next lesson we will continue to work on the dialogue system so it will be able to handle branching dialogue as well.