Hey there folks. I’d like to share something I’ve been working on for the past few months with you. Hopefully, given enough interest and a bit of time this tool will find its way to the marketplace.
This tool came forth from a personal gripe of mine that it is currently impossible to properly create branching dialogs in Unreal Engine. Doing it in Excel or some other “linear” editor makes it a gigantic pain when dialog choices mean that you can jump around different lines or even loop back. And let’s not mention any more complex stuff. Thus, after a lot of research, some tinkering and a lot more work, I am proud to present my Integrated Dialog Editor.
Important: Before reading on I’d like to clarify that this is a system for creating dialog data only. There are no UMG components or logic to actually display this data to the player. The dialog system is used to create and “traverse” dialogs. It is the developers choice how to display and use this data in their games.
Create complex branching dialogs easily using the familiar Unreal Engine graph editor. Dynamic branching is controlled via Flags that can be driven by outside events. Special conduit nodes work in a similar fashion to Select nodes in BehaviorTrees, in that the first node whose flag is set will get executed. Flags can be set per dialog or on a global level.
Each dialog line can be fully customized with a ton of integrated data. You can associate speakers, sound cues and animations to dialog lines, as well as add any number of dialog choices. The availability of lines as well as choices in lines is dictated by the set flags. Similar to FText::Format, you can use format wildcards in dialog text and feed values in later on when you start the dialog. Dialog speakers allow you to define all the actors of your game and associate various properties with them. You can assign a skeleton that will be used with this speaker. This will in turn be used to filter the animation list for the dialog lines that use this speaker. Conduits can be nested to control the flow of the dialog as complexly as you need it to be. Since these dialogs tend to loop back quite a bit, redirect nodes are fully supported.
When starting the dialog from Blueprint (or code) you can fully customize all initial parameters as well as feed in data for wildcards. All of this can be done at any point during the dialog as well of course. It is important to note that it is fully possible to retain the state of a dialog if it’s canceled before it ends. This can be useful when it’s important to save and restore a dialog state such as with visual novels or Ace Attorney-style games.
Flags can be set or unset via the API dynamically but it is also possible to associate functions with flags to have them be queried automatically when the dialog system encounters the specified flag. These functions can be as complex as you need them to be.
You can hook into all of the important events and drive any and all of the game logic you can think of based on what happens in dialogs (Camera transitions, monster spawns, level loads etc.)
Everything in the plugin is using FText and as such fully supports localization.
In addition to these, there’s an optional system to assist with creating dialog camera transition. The system works in four steps. All of the techniques shown can be used partially, or not at all. This is completely optional.
1. Set up the type of scene for a particular dialog line
During dialogs, no matter how big or small, different characters (singular and plural) are being focused via different camera shots. These can be set per-line and can have the following variations:
- None - Disabled. The scene system has absolutely no performance overhead if not used.
- Any - Any scene that contains the current speaker and is associated with this dialog will be eligible. Picked at random.
- Speaker - Get the focus shot of this speaker. More on this in a minute.
- Player - Get the focus shot of the player character. Same as above.
- Matinee - Play a matinee during this line.
- World - Get a world shot that contains all speakers specified in a list. If there is no such shot, it will fall back to “Any”. I thought about renaming this “Group” but really, you can set it to show anything, focus on furniture or some mountains etc.
- Labeled - Get a specific named shot, marked by a FName label.
2. Set up speaker shot configurations
Most games that have dialogs (namely RPGs) usually have one common camera angle / position that the camera focuses on when the player talks to NPCs. To this end I’ve set up a new asset type called SpeakerCameraSettings.
This is used to define the socket and offset of where the camera will be positioned, and the socket and offset the camera will be look at. This can then be reused in all your NPCs. Note that the set up is an array. If the two trace settings are turned on, when selecting a position, the system will go sequentially through the array and select the first setting that passes the tests (or has both tests turned off). This is to be able to define several presets (like over the shoulder left, over the shoulder right etc.) and avoid the camera clipping through walls if you have wandering NPCs.
3. Mark actors in your world as speakers
To actually mark actors in your world as speaker, you attach the new SpeakerSettingsComponent to them.
This simply tells the system which speaker this actor is, and what configuration to use for this speaker.
There are BP exposed functions to change both of these at runtime. For example, you could have a telephone that you can “talk to” and it ends up being several speakers.
4. Create World shots
Last but not least, to facilitate static shots, group shots and such, you can use the new DialogSceneCameraActor.
This camera actor can be used in several dialogs and the list of speakers in it can be adjusted at runtime. Currently I am working on making it automatically check which speakers are in view of this camera, although this check might end up being expensive and is of dubious usefulness. Perhaps a more useful feature would be to have the camera rotate to focus on the current speaker.
Either way, in addition to the speakers you can also tell this particular camera to use a matinee. What happens in that case is that a matinee will be played instead of switching to this camera. However, it is of note that in your dialog lines, if the scene is set to Matinee you can also define what scene will be used AFTER the matinee, in case the player hasn’t advanced to the next line.
If this isn’t set, and the matinee finishes playing, the camera will switch to the camera actor that started the matinee.
- Sequencer Support
- Additional Documentation
Automatic Sound Cue playback
Binding Event Flags via C++
- CSV Import & Export
- Collapsing / expanding parts of the graph
- Line Node Prettify
- Text in dialog nodes flickers if it’s too long
Right now I am focused on debugging and polishing the core features; making sure everything is as user friendly as possible. If any other features come up internally or are requested I’ll attempt to work them in before moving onto the marketplace submission
If you have any questions, suggestions or comments, I’ll be more than glad to read them! Let me know in this thread!
Q: Alright but what about Slate / UMG? What do I do with this data?
A: As I said earlier, this is data only. It handles the flow of the dialog based on flags and whatnot under the hood. It is up to the specific game to implement their UI and a way to display the data. For example, when you talk to an NPC, you’d pass his dialog object to the HUD, bind all of the events for that dialog and show your UMG widgets that display the speaker name / dialog text etc. when the dialog starts, change the text after you call MoveToNextLine and hide it all inside of OnDialogEnd. The example project contains a simple set of widgets that you can use as a reference point.
Q: How long will you maintain and update the plugin?
A: This plugin started out of necessity as I needed a dialog editor for my studio’s project. That project will be developed for the next few years and I will be updating and perfecting the plugin in a real-world environment to make sure it’s as awesome as it can be!