Fluent Dialogue

Overview

This is a dialogue conversation framework for unity. Conversations are defined using a fluent api in code.

Features

  • Speech bubbles
  • Conversation trees
  • Multilingual
  • User definable UI
  • Define variables and logic directly in C#

Note that MonoDevelop has some text formatting issues. I recommend the free Visual Studio Community.

 
W/A/S/D to move E to initiate conversation

0: Hello World!

Code

To create a FluentScript we inherit from FluentScript, which is a Monobehaviour, and override the Create( ) method. In this first example the object this script is placed on will Yell “Hello World” when the script is executed.

Setup

Add an empty GameObject to the object you want to yell. Here the object that will yell is called NPC 0 and the empty game object is called Talk.
 

We then add the Conversation 0 script to Talk. In this example talk also needs a collider so that we know when we are close enough to talk to NPC 0.
  

Yell shows the first canvas it finds in Talk. It then sets the first Text it finds within that canvas to “Hello World”. Note that the FluentScript’s output is presented as a tree under “Root”.

Initiating the conversation

To initiate a conversation we need to call Run( ) on the FluentScript. You can do that any way you’d like, but for the examples there is a script called FluentManager. If you would like to use FluentManager then add an empty GameObject to your scene and add FluentManager to it.
 

On FluentManager set the Text UI element that will notify the player that there is something to talk to, as well as set your player.

1: OnStart() and OnFinish()

Code

Override OnStart and OnFinish to specify what should happen before and after a FluentScript starts and ends. Here we disable player movement.

Encapsulate

Since we always want the player not to move when a converstation starts we encapsulate that information in a new class called MyFluentDialogue

We will from now on inherit from MyFluentDialogue instead of FluentScript

2: Response Chain

Code

Yell is one of many FluentNodes, we can chain nodes. In this case we yell 3 times. A FluentNode completes before the next one in the chain is executed. Note that we need to use * to join them.

3: Others Yell

Code

Yell takes an optional parameter to specify the object that should do the yelling. Note that the specified object should have a canvas with a Text UI element.

4: Options Presenter

Code

In this example we introduce a new FluentNode called Options( ), which contain one or more Option( ) FluentNodes. Option( )’s first argument specifies the text that will be presented to the user. The FluentNodes following an Option( ) will be executed when that option is selected. Options are presented by an OptionsPresenter.

Setup

An OptionsPresenter script needs to be added to your Talk object to show options.
 

On the OptionsPresenter you specify 3 things

  1. Dialog UI is the UI element that will be SetActive when the Show() or Hide() FluentNodes are executed.
  2. Option Item UI is a prefab that will be used for your Option Items. The Option Item prefab needs to have a Text component, which will be set to the specified option text.
  3. Options Panel is the panel that will be used as the container of the option items

5: Write

Code

Here we introduce a new FluentNode. The Write node will write text to a specified UI element.

Setup

We need to add a WriteHandler to the talking object.
 

There are 3 things we can specify on Write Handler

  1. Text UI is the Text UI element the text will be written to
  2. Seconds / Character is the delay per character while writing
  3. Optionally Button Element is the button that will be shown after the text has been written. The user will have to press the button before execution continues

6: Branching

Code

This example shows that an Option can have an Options FluentNode as one of it’s children. Use Back( ) to instruct an Option to cause the dialogue to go back up the tree.

7: Running Code

Code

Here we introduce a new FluentNode. Do executes a delegate.

8: VisibleIf

Code

There is a method on Option called VisibleIf( ) which takes a delegate, if that delegate returns true then that option will be shown.

9: Click Initiator

Code

By default FluentScript looks for a GameActionInitiator, if it doesn’t find one it automatically adds a ProximityInitiator. For clicking to work we add the ClickInitiator script to our object.

10: Parallel Chains

Code

Here we introduce a new FluentNode. Sound( ) will play an audio resource. There exist cases where we want multiple FluentNodes to execute at the same time. Playing sounds while text is being written is a good example. The nodes specified in a Parallel node will all execute at the same time. Parallel will only complete once all it’s parallel nodes have finished. Note here we created a helper method that combines writing and playing sound in one convenient method.

11: Only Once

Code

Nodes within Once will only be executed once for the current conversation, but will happen again if the conversation is restarted.

12: If

Code

Here we introduce a new FluentNode. The If node takes a bool delegate as it’s first parameter and a fluent chain as it’s second. The fluent chain will be executed if the bool delegate returns true. It is important to note that the visited number string concatenation in this example is evaluated before the Do() response is executed. If you would like the string to be evaluated at execution time then you need to use Eval(( ) => “Visit number ” + timesVisited)

12: Multilingual

Code

14: ContinueWhen

Code

Here we introduce a new FluentNode. ContinueWhen polls the passed in delegate and continues down the fluent chain once the delegate return true.

15: Custom Conversation

Code

Here we again extend FluentScript, this time by allowing us to set an image of our NPC in the editor.

16: While

Code

While, like If, takes a delegate as the first parameter and a fluent chain as the second. In this example the conversation will continue until stillFighting is false.

Leave a Reply

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