NPC Dialogue System Tutorial
__NoToc__ Authored by: Adam Davis Special Thanks: Zeustiak, Rudy Triplett, Ian Shadden (all three provided some information on different aspects of this system that assisted in making it more stabl...
__NoToc__ Authored by: Adam Davis
Special Thanks: Zeustiak, Rudy Triplett, Ian Shadden (all three provided some information on different aspects of this system that assisted in making it more stable). I also want to thank Alexander Paschall again for Daniel, the Chicken. He comes in handy!
Introduction
In many games, the need arises to have a variety of NPCs that the player can interact with independent of other units. Quest givers, party members, even static conversations with trivial NPC units can have an impact on the feel of a game. This system was designed to replicate a fully branching dialogue tree without the use of conventional tools such as data tables. The purpose was to see how possible it was to fully integrate an NPC system into a game with nothing but blueprints. The goal is for the user to be able to interact with Daniel, the Chicken. He is going to be the basis for our NPC blueprint.
Something to consider here is that I did not remove the playerÔÇÖs ability to move as it was not necessary for this tutorial. However I feel it should be noted that this makes controlling the widget at first a bit difficult and you may wish to consider disabling player movement or possessing another player controller with no movement until the conversation is over, in which you return to the original play state. This has not been implemented here but something that may be worth looking into.
Blueprint setup
To begin, create an Actor Blueprint. Mine is named ÔÇ£TextRenderingActorÔÇØ but any name will do. While you are at it, create a widget blueprint. The one I used in this example is just called widget. This isnÔÇÖt a good name for a project, especially when you will have more than one of these available, so I would recommend using a different name. The components you will need for this setup are fairly few. As you can see below, all I used was a scene component to hold the root. Then a box component scaled so that the player can walk into it, a skeletal mesh (Daniel), and a text render actor.
This blueprint does require a number of variables, most of which are public so they can be edited to fit each individual NPC. In my example I have 12 different arrays, which have a number of variables for each ranging from 1-3. All of these as well as the ÔÇ£I must goÔÇØ variable are public. The array variable is extremely important to the UMG setup so make sure to have a text array variable in place. Ours is called ButtonText. Additionally, you will need at least two int variables. One to update your selector and one to affect how the function interacts with your button presses. I named these Update Array and Int.
Event graph
The first thing you need to do is make sure that your player can interact with the NPC once it is overlapping with the Box Component. Create an On Actor Begin Overlap and On Actor End Overlap. Additionally, go ahead and create a custom event, call this ÔÇ£LeavingÔÇØ. This will come into play in just a little bit, but for now, you want to go ahead and have it. From the begin overlap, create an ÔÇ£Enable InputÔÇØ node, and make sure that the player controller is tied to your player controller (a Get player controller node will do the trick). Plug in a set text node after this, which should be set to your text render actor in your NPC blueprint.
Now that you have this set up, go ahead and make a ÔÇ£Create widgetÔÇØ node, with the class set as your widget that you set up earlier. The owning player again should be your player controller. The next step is create an Add to Viewport node, with the target set to the return value of your create widget node. This will set the widget to your viewport.
Cast to your player controller and from the ÔÇ£As Player ControllerÔÇØ output pin, get a ÔÇ£Set Show Mouse CursorÔÇØ node, check the checkbox to set it to true. This is necessary to be able to interact with the UMG widget. Finally, get a set of your text array.
For the End overlap (and Leaving custom event), you will simply be undoing the actions you did in your begin overlap. Create a disable input node, set your text in your actor (I used goodbye), set the Update Array var to 0 (this will be explained shortly), remove the widget from your viewport, then cast to your player controller and set show mouse cursor to false. This can be seen in the above image.
Set Events for Text Actions
This is by far the easiest part of the tutorial! You deserve a breather afterall. All you need to do is create 4 custom events. I labelled mine Answer1, Answer2, Answer3, and Answer4. For the first 3, do a separate set Int (your second integer variable) and set it to 0, 1, and 2 as seen below. All three of these need to be plugged into your Question 0 Response branch, which we will get to in just a moment. What these do is set your integer value to a specific number so that it can alter which dialogue options you get based on the choices you make.
For Answer4, all you need to do is create a function for your ÔÇ£LeavingÔÇØ custom event that you created earlier. Right click and type in ÔÇ£LeavingÔÇØ.
Arrays and the Selector
This array of arrays is what stores your responses to the prompts from your NPC. Create as many arrays as you require for your NPCÔÇÖs and make sure to set the number of responses for each one. For instance, if you only want the player to have 2 options for a specific question the NPC asks, only add in 2 text variables. Additionally, make sure that you make these public so you can edit them from the details pane.
The next part is creating the selector. All you have to do is type ÔÇ£SelectÔÇØ into the context menu and it will show up. This node is very powerful, but it is also extremely fragile. Before adding anything to it, make sure you have the exact number of input pins for your arrays. So if you have 12 arrays, make sure to have exactly 12 input pins. If you have any pins leftover it will not compile and will throw warnings into your script until you delete the node and recreate it or find more arrays to fill the additional nodes. Anytime you alter the amount of arrays you are using you will have to create a new Selector. To add option pins, right click the node and press ÔÇ£Add Option PinÔÇØ.
Set your index to your Update Array variable. This is the main reason it is important to set the update array to 0 when you leave the overlap. This will 0 out the information held so that the conversation can start over when you re-enter the overlap. You can also ignore this to save the conversation at a specific point if you want to. Plug the output pins of your arrays into each option of the selector in the order you want them to appear. Additionally, take the array output from the first array and plug it into your ÔÇ£Set Button TextÔÇØ from the ÔÇ£Begin OverlapÔÇØ function created earlier.
Setting up branching response paths
The final step to finishing your blueprint is to tell the blueprint what to do when you make specific selections. Create a branch node. All of your input custom events (Answer1, Answer2, Answer3) should be plugged into this branch. The only one you will want to keep away from this is Answer4, because that deals specifically with getting out of the conversation.
This branch should check to see if the Update Array Int is equal to 0, if it is not, it will move on to the next in the series (Update Array == 1) and so on and so forth. If it is true (this is true of each case), the branch runs a series of checks. If the input you selected set Int to 0, it sets the text render actors text to a specific value (In my case, ÔÇ£Would you like to take a nap?ÔÇØ) then it updates the Update Array to a new value, in my case, 1. This is designed to take you to a specific array in your selector for your new set of responses based on the NPCÔÇÖs reaction.
You run this same check for if the player pressed the second or third button (Int 1 and Int 2, respectively) and update the values accordingly. It is a good idea to note that much of this, specifically the branches, can be set to a function so that it looks much cleaner. I did not do this so I could walk through each step of the process.
This determines what response you gave and sets the NPCÔÇÖs reaction to what you said, then updates Update Array to choose a new set of responses based on the answer you gave. Finally, all of your choices should lead to a ÔÇ£set Button TextÔÇØ node. Make sure to attach the Array output from your selector node to the input of the ÔÇ£set Button TextÔÇØ node.
Once you are done with these steps, your blueprint will probably look a little something like this:
UMG
The first and easiest step to the UMG system is to create your buttons. Do this by dragging the widget ÔÇ£buttonÔÇØ onto the design window and resizing it to where you want it. Then make sure it is placed as you prefer. For this example, we are placing them directly in the center of the screen so it is easy to access. Finally, add a Text block directly onto each button so that it is parented to the button.
To set up the click events for the buttons, Go to your design tab and select a button, then in the details pane, go to the events subsection and press the ÔÇ£Add OnClickedÔÇØ button.
For each button, do a ÔÇ£Get all Actors of ClassÔÇØ then a ÔÇ£ForEachLoopÔÇØ, casting to the NPC character. Then drag off of the ÔÇ£as NPCÔÇØ pin and call your custom input events.
Next, select one of your text blocks in the widget design tab. Press bind in the ÔÇ£ContentÔÇØ section of the details pane, then ÔÇ£Create bindingÔÇØ.
Once you have created the binding, you need to get all actors of class for your NPC Blueprint. Run the Out of Actors pin to a for each loop, which will run a cast to your NPC Blueprint. Finally, you need to get the temporary variable holding your array. Set each of your text blocks in the same way, choosing the specific index from the responses in your array manually (for instance, for the first block I did array index 0, the second 1, and the third 2).
The only difference between the regular responses and the leaving response is the variable you call. Instead of getting the temp array, call your ÔÇ£leavingÔÇØ variable, in my case it is the ÔÇ£I must goÔÇØ variable.
A practical Example
Here is what the system looks like when used as above. Keep in mind, you will want to customize the text variables and the string values to fit your needs as well as how many arrays you need. Let us start by walking up to Daniel, who gives us a warm greeting with 4 response choices:
After choosing the first response, you are given a whole new set of responses to the new text prompt:
Once you make a choice for the next set of responses, it travels down the line to an entirely new branch:
When you first approach and choose the second option, which was a bit mean, it elicited an entirely different response and subsequent player choices because of it:
If you chose the third response, you get yet another set of options!
Finally, the system has the built in leave option so you arenÔÇÖt forced to stick out a conversation if you donÔÇÖt want/need to:
This system can be used to create multiple branches of a dialogue tree, and allow you to customize multiple copies of the blueprint for your specific needs, quickly populating your game with random NPCÔÇÖs, quest givers, conversations between player characters, etc. Take a look and see what you can come up with!