How to Create a Simple Dialogue and Interaction System in Unreal Engine

True Outlaw
10 min readFeb 28, 2023

--

I’ve recently been working on a project using Unreal Engine, and I needed to create a simple interaction system in which the player character could interact with objects and NPCs (Non-Player Characters). I’ve worked in Unreal Engine before, but my expertise lies solidly in Unity — I was hoping to use this project to up my skill level and become a more versatile developer. It was interesting trying to translate concepts I know from programming in Unity to Unreal, and I definitely learned something. Because it’s different enough to most of the other tutorials I found online I thought I would create my own in case it helps someone down the line.

In this tutorial I’ll cover:

  • How to set up a general interaction system
  • How to display a popup above an object (when the player is nearby and facing said object)
  • How to display some sort of text (dialogue or information)
  • How to cycle this text when the player presses the interact button again

Throughout all this, my aim was to make the system as scalable as possible in order to avoid rewriting the same functionality over and over again for each new Blueprint created. I’m not sure I achieved this goal perfectly, so any feedback you may have after reading through this would be greatly appreciated.

Now on to the tutorial!

In my investigations, there are two main approaches to creating an interaction system in Unreal Engine — using interfaces and line-tracing with the code sitting in the player blueprint, or using collision detection on the interactable object itself and casting to an actor like the Player Controller. I went with a kind of combination of the two.

My approach was as follows (if you’re familiar with Unreal Engine, this may be as far as you need to read):

  • Create an interface containing all the function definitions I’d need
  • Implement collision detection with overlap events in front of my character, which calls said functions

I didn’t use line, box, or sphere-tracing for this tutorial, but it would work using those methods as well.

Alright, so, to get started, right-click in the Content Browser, search for Blueprint Interface, and create a new Interface — I named mine IInteractable.

Open it up, and create the following functions:

That’s it! Feel free to close the tab as we setup some UI.

Create a new Widget Blueprint (found in the UI section when you right-click in the Content Browser), and name is WB_Prompt, or whatever else you like.

Open it up, and add a Canvas Panel, Image, and Text. I renamed the components as shown below.

Feel free to set the canvas up as you like. Here‘s what mine looks like:

Now, it’s time to create the Base Class for what we’re going to interact with. To do that, create a new Actor Blueprint (I just called mine BP_Info, which is a bad name in hindsight, so feel free to rename it). I added a static mesh to its list of components, and set it to be a cube, just so we have something to see for now. I also changed the collision settings to that which is shown below:

Then, add the WB_Prompt to the list of components by adding a Widget Blueprint, and choosing WB_Prompt from the Widget Class selection menu in the Details Panel. I also changed it’s position to appear above the box, slightly tilted since my game is from more of a top-down perspective.

Nearly there. Set the widget’s visibility to hidden:

And then, open the Class Settings to implement the IInteractable interface:

Great! Now to show the prompt.

Create a CanInteract event in the Blueprint, either my right-clicking the function in the Interfaces section in the My Blueprint window on the left, or in the main Blueprint window.

Get a reference to the WB_Prompt object we created, and set its visibility to true, like below:

Place the Actor in the world, a slight distance away from the player. This won’t work just yet — we still need to setup the functionality in the player.

In your player Blueprint (I’m using the Third Person Character template), create a Box Collision (or whatever tracing system you’d prefer), and set its collision settings to those listed below:

Size the box how you’d like, but make sure it’s not overlapping the player’s capsule. Mine it out front, like this:

Then, add the interface to the class settings as we did before.

The final step before we can see the prompt though, is to trigger the event we created. To do so, create an On Component Begin Overlap Event (by selecting the Box Collision and scrolling right to the bottom of the Details Panel). Create the following variable and nodes off it:

And finally, you should be able to see your prompt showing up when the player gets close enough and is facing the box. But, the prompt won’t disappear again, which is easy to fix. Just create an On Component End Overlap event in the same way as before, and create the following nodes:

And then add the following to your BP_Info:

As a side note, the Is Valid checks can be condensed by right-clicking the variable to create a Validated Get, which might save you some time and space.

To wrap it all up nicely, create an event for your input action. Currently I’m using the new Enhanced Input System, so creating an action was a bit more involved than usual, but either way, in your character Blueprint, add the following:

Use the Validated Get here too if you’d like, and add the last bit of functionality to the Start Interact event:

And that’s basically it. Now you can add any functionality you want to the Start Interact function in your BP_Info and you have a basic Interaction System.

Now the very basics of our system are in place. You should now know how to create the further functionality you need going forward. If you want to find out how I implemented a simple Dialogue and/or Information system (for things like in-game signs), stick around, but this is where things get slightly more complicated.

Alright, now for the Dialogue System. First, right-click in the Content Browser and create an Enum (found under the Blueprints section). I named mine E_InteractionType, as this will be used to distinguish which widgets to display to the player. If you only want to create a dialogue system, you can skip this (and the next few) step(s).

Next, open up the enum, and give it two values, Information and Dialogue.

Now open up your BP_Info and create a new variable called InteractionTypeMap. Set it to be a Map, its key to be the enum we created, and its value type to a User Widget Class Reference.

Now create the following variables:

None of them need default values, apart from the InteractionTypeMap, but we’ll get back to that.

Next, we need to create some UI to display. For the purposes of this tutorial, we’re going to create two UI that are identical, with the intention being that you can edit them to suit your purposes later.

Create a new Widget Blueprint, name it WB_InformationDisplay, and set it up any way you like as long as it has a text component we can use. This is my setup:

EDIT: When I last published this article, I left out vital information for the proper setup of this system. What follows is a correction to that.

To finish setting up the UI, create a variable called TextToDisplay and set it to be of type Text. This will probably get confusing a bit later, so if you can come up with a better name I recommend naming it that.

Go back to the designer and select the Text UI you want to display the dialogue or information, and in the Details Panel, under Content, click the Bind dropdown next to the Text field.

Click on Create Binding.

This will open the Graph View. Drag the TextToDisplay variable into the return node of said function. This will ensure that whenever the this variable is updated, it will update the text of the UI.

In the Designer View, your Text field should look like this:

Now duplicate this Blueprint and name it WB_DialogueDisplay. Feel free to design this one how you like to distinguish the two.

Then, go back to BP_Info, and assign the new Widget Blueprints you created to the InteractionTypeMap. By the way, there seems to be an issue with Maps, so if it gives you an error, delete the “default” value, add the second Blueprint, then re-add the default value again.

Add a Validated Get for the Displayed Widget variable to your Start Interact event, after the Set Visibility function call.

Then, create a new function called UpdateTextToDisplay. Inside, it should look like this:

You won’t have the ResetUI function yet — let’s create that next:

Alright. If you need an more in depth explanation about the above functions feel free to reach out, but essentially they update the text to display in the UI each time the Interaction button is pressed, and if there’s no more text in the array, it removes the UI from the screen and reactivates the prompt, as well as resetting which text to display back to the 0 index.

Next, create a function called SetTextToDisplay:

This updates the text based on which Widget Blueprint it is. Maybe this isn’t the best method, because if you add more classes you’d need to update this function, but I don’t think I’ll need any more UI besides this for my case.

Finally, create one more function and call it AddWidgetToViewport:

This will add the specified widget (that can be set in the level editor) to the viewport.

Now, back in the main Event Graph, link up your functions like this:

And do the same for the Stop Interact event:

And finally, back in the main viewport, select your BP_Info actor in the scene, find the Default section in the Details panel and set the variables:

And there you have it! When you interact with the actor, it should show something like this:

I hope you found this useful and easy enough to follow and understand — if there was anything I didn’t explain in enough detail, or if the tutorial in general was overcomplicated, please let me know.

Otherwise, I hope this has or will one day help you in one of your projects, and if you feel inclined to share I would love to hear back from you if you’ve found this useful and have found a place for it in something you’ve created. You can find me at True Outlaw.

--

--