michael puskas

Building a complex text display system in UE4

 

Dialog

 

For the past 9 weeks, I’ve been working on a text adventure in Unreal Engine 4 (Why UE4, you ask? You’ll have to wait until it comes out to see.) Today, I am finally calling the systems/framework complete, and can progress onto the writing stage. Before I do that however, I wanted to make some notes about how I implemented my text display system. Since UE is obviously not made for text adventures, I had to do a lot of searching to find the relevant information. With this post, I hope to condense it down for anyone in the future that has a similar goal.

 

The above gif is of the final result. I’ll be covering my implementation at a high-level, but I would be happy to write some follow-up posts with code examples and rationale if anyone is interested.

The problem will be framed as such:

  1. How do you lay out the widget blueprint?
  2. What does the printing logic look like?

 

1. How do you lay out the widget blueprint?

The first problem is getting the text to originate at the bottom of the widget and scroll upwards. The standard text widgets don’t allow this, so I turned to the UE forums for some help. ‘Everynone’ was kind enough to lay out a blueprint for me that does (almost) exactly what I wanted.

 

The basic idea is to place a scroll box inside a border, create a new widget that only contains a text widget (WLabelListItem in Everynone’s example), and add an instance of the new widget whenever we want to add text. I kept a reference to this widget to print the characters within it one-at-a-time, but we’ll cover that in the next section.

 

Lastly, something that is a part of the larger UI design but that I’ll mention here, is the animation that I added to the Border. I can call a function to fade it in/out, and I have logic in my Process function to wait for the animation to finish before printing any text.

 

 

2. What does the printing logic look like?

There was a lot to consider when printing the text. Firstly, I implemented a dialog buffer with some logic that I attached to my UI widget’s Tick event.

 

Tick

 

This buffer consists of a float BufferTimer that I use to track the time between prints, and an FString Buffer that I append dialog to whenever I want to print something. On every tick, the Process function checks if there’s anything in the buffer, and, if so, runs through some logic to process and potentially print it.

 

This function first checks:

  1. Are we currently animating?
  2. Is there anything in the buffer?

 

If we get a no and yes, then it subtracts the DeltaTime from the BufferTimer. It then checks if the timer is <= 0, and proceeds.

 

Here is where I’ll do some hand-waving. The rest of the logic solves a few problems that I came across and, as I said before, I will be happy to share it if anyone wants some code. For the sake of keeping this post manageable though, I’ll just list the cases that I handle:

 

  1. If we’ve added the first character of a new line, scroll the Scrollbox to the end (To bring the new line into view. You need to wait for 1 character to be added or else it won’t scroll far enough.)
  2. If the character is a number, chop it off the dialog buffer, but instead of printing it, set the BufferTimer equal to that number. (To enable the scripting of pauses.)
  3. If the next word is too long to fit within a 90-character line, insert a newline.
  4. If the buffer is empty, do what must be done to continue the game. (In the gif above, setting the Proceed button to visible)

 

After all of this, we get a robust system that allows us to push text to be printed whenever we want, without forcing the main game logic to handle it.

 

 

Additional Notes

I pull all of my text in from .csv files for easier editing.

 

I can insert numbers straight into the .csv to add pauses in the printing. Since a certain atmosphere and tone are integral to my goals for the game, this was a necessary feature. Having a way to add pauses while I’m writing the text in Excel makes my workflow very smooth.

 

 

That’s all, folks.

Hopefully this was helpful, either directly or as inspiration. There’s plenty more that I could flesh out, and I might make another pass at this post at some point, but for now I’ll leave it how it is and see if anyone has any questions.

 

-Michael

Leave a Reply

Your email address will not be published. Required fields are marked *

© Michael Puskas, 2016. All rights reserved.