Make Options Timeout
This sample demonstrates how to create a custom dialogue presenter where dialogue options include a timeout bar. When options are presented, the timeout bar gradually shrinks. If the player doesn't select an option before the timer expires, the system automatically selects one for them.
The sample supports three variations of this functionality:
A hidden option that gets selected when time runs out
A visible option designated as the default that gets selected when time runs out
The currently highlighted option gets selected when time runs out
For simplicity, this guide focuses on implementing the first approach. To explore the other methods, check out the full sample. LINK TO SAMPLE
video of it in action here?
What we'll be covering
Custom Dialogue Presenters
Using Metadata to control views
The nightmare hellscape that is Unity UI
If you want to see a finished version of this go to PATH TO SAMPLE.
Building the scene
If you haven't already install Yarn Spinner link to install guide. Once installed we will start by building out a basic scene.
Make a new scene in Unity.
From
Samples/Shared Assets/Prefabs
drag the Basic Arena into the sceneFrom
Samples/Shared Assets/Prefabs
add a Camera Rig into the sceneFrom
Samples/Shared Assets/Prefabs
drag a Player prefab into the sceneFrom
Samples/Shared Assets/Prefabs
drag an NPC prefab into the scene and rename it to beAlice
Add a default dialogue system to the scene, in the Hierarchy right click
Yarn Spinner -> Dialogue Runner
Create a new Yarn Spinner project
Assets -> Create -> Yarn Spinner -> Yarn Project
and name itTimeout Dialogues
Create a new Yarn script
Assets -> Create -> Yarn Spinner -> Yarn Script
and name itAlice
Delete the previous camera called
Main Camera
The Dialogue
Replace the contents of the Alice Yarn script with the following:
This script contains a single node with three options. Only the first two will be visible to the player. The third option (marked with the #fallback
metadata) will be hidden but selected automatically if the timer expires before the player makes a choice.
Configuring the scene
Select the Camera Rig and in the inspector drag the Player into the target field
Select Alice and in the Inspector set the Dialogue field to use the new
Timeout Dialogues
projectSelect Alice and in the Inspector select the Alice node in the dropdown
Select Alice and in the Dialogue Runner field drag in the Dialogue System object from the hierarchy
Select the Dialogue System and in the Inspector set the Yarn Project to use the
Timeout Dialogues
project
Making a Custom Options Presenter
At this point, you can talk to Alice and go through the dialogue, but the timeout functionality isn't implemented yet. Now we'll create our custom presenter by building a UI bar that shrinks over time, then develop a custom dialogue presenter that uses it.
Making the Bar UI
First, we'll create the UI elements for our timer by modifying the existing canvas from the Dialogue System prefab.
Right click on the Dialogue System in the hierarchy and choose
Prefab -> Unpack Completely
This will disconnect this from being a prefab but will otherwise leave it in the state we want.Expand the Dialogue System out in the hierarchy so we can see all the individual components we are interested in the children and grandchildren of the Option View gameobject.
Select the Last Line game object and delete it. While we could handle also showing the last line it would just add more logic to our view while not actually showing off the main feature of this sample. So instead we'll just drop it.
Add a new empty child gameobject to the Options View and name it
timer container
, this will be what holds our timer bar. By default it will have inherited a slew of position and size properties from it's parent's vertical layout group, which is mostly what we want, but we do need it to have a specific height.In the inspector add a new Layout Element component to the timer container.
Tick the Preferred Height field and set it to have a height of
30
. Now this element will tell it's parent layout group that it is going to be 30 units high which is perfect.Add a new empty gameobject to the timer container and name it
timer bar
.Give the bar an image component.
Change the bars rectangle widget to be centre-aligned + vertical stretch.
Set the width to be whatever you like the look of, we found that 1480 units was a nice value.
This bar will shrink as the time to select an option runs out.
Our UI work is now complete. Next, we'll write the code to make the bar shrink over time.
Create a new monobehaviour script and name it
TimeoutBar.cs
Open up the new file and replace the imports with the following:
Add the following fields to the class:
These fields represent the bar UI element and its original size, which we'll use to reset it between option sets.
Replace the
Start
method with the following:
When Unity initializes the component, we store the default bar size in originalSize
for later reference.
Add the following new method:
This method resets the bar to its original size. There are several ways to accomplish this, but using SetSizeWithCurrentAnchors
is straightforward and lets Unity handle the rectangle's final dimensions.
Add the following new method:
This method gradually shrinks the bar over the specified duration. It first verifies that the bar exists, then enters a loop that continues until either the duration elapses or cancellation is requested. Each iteration updates the bar size using linear interpolation from its current size toward zero. After the loop, we ensure the bar is fully shrunk regardless of how it exited the loop.
Add that class as a component to our bar
Drag the bar gameobject into the Bar field in the TimeoutBar inspector and now the bar is done.
To see a complete version of this check out path to the file in the samples.
Making the custom presenter
Now we'll create the custom dialogue presenter subclass. Since this involves substantial code, we'll approach it in sections.
Create a new presenter subclass
Assets -> Create -> Yarn Spinner -> Create -> Dialogue View Script
and name itTimeoutOptionsView
. This creates a stubbed out subclass with all the necessary methods for a custom view.Replace the imports with the following:
Add the following fields to the class:
These fields reference the UI elements we need to manage: the canvas group for fade effects, the option item prefab, the timer bar, and a list to cache option items. Other than timedBar
, these are similar to what you'd find in the default options presenter.
Add the following fields to the class:
These fields control the timing aspects: how long the player has to select an option before timeout, and the duration of fade-in and fade-out animations.
Add the following field to the class:
This constant identifies the option that should be selected when the timer expires. We'll use it later when examining option metadata.
Replace
OnDialogueStartedAsync
with the following:
Replace
OnDialogueCompleteAsync
with the following:
These methods are called by the dialogue runner at the beginning and end of dialogue. Both hide and disable the options UI, then return a completed task.
Replace
RunLineAsync
method with the following:
Since this presenter only handles options, we can return immediately when asked to run a normal line.
Replace
Start
with the following:
Similar to the dialogue event handlers, we initialize the UI as hidden and non-interactive.
Finally add a new internal enum to the class:
This enum identifies which timeout behavior we're using. The default is None
, meaning no timeout is needed for the current option set.
Determining the Timeout Type
Now we'll implement the RunOptionsAsync
method, starting with determining which timeout option to use and validating the option group.
Inside the
RunOptionsAsync
method add the following code:
These variables will track whether we need a timeout and which option should be selected if timeout occurs.
Add the following code:
This code examines all the options to find any with the fallback
metadata tag. If it finds one that's available, it marks that option as the hidden fallback to be selected when the timer expires. We also count how many tagged options we've seen for validation purposes.
Add the following code:
This validation ensures that if we're using a hidden fallback, we have exactly one option tagged as such, and we've successfully identified which option it is. If either condition fails, we log an error and tell the dialogue runner that no option was selected.
Handling Cancellation and Completion
Next, we'll set up the infrastructure to handle completion and cancellation. These mechanisms will be provided to the option items later.
Add the following code to create our completion source:
Add the following code to create our cancellation source:
These sources work together to handle the two possible outcomes: the player selects an option, or the dialogue is cancelled. Now we'll implement the cancellation handling:
Add the following encapsulated method:
This task monitors for dialogue cancellation and ensures proper cleanup by setting a null result on the completion source if needed. This connects the two sources: if dialogue is cancelled, this function sets the completion value on selectedOptionCompletionSource
.
Creating and Configuring the Option Items
Now we'll create and configure the option items to display to the user:
Add the following code to instantiate new option items as needed:
This creates just enough option item prefab instances to handle the current option group, reusing any we've already created. The CreateNewOptionView
method will be implemented later.
Add the following code to configure the option items:
This code configures each option view with its corresponding option data, skipping any that are unavailable or marked as hidden fallbacks. It then selects the first valid option to be highlighted initially.
Add the following code to enable or disable the timer bar:
This activates the timer bar only if we're using a timeout option, resetting it to full size and ensuring it appears at the bottom of the option list.
Fading it all in
Now we'll display the UI to the player:
Add the following code to fade in the UI:
This fades in the UI and enables user interaction once the fade is complete.
Add the following code to start the timeout bar if needed:
If we're using a hidden fallback option, this starts the timer that will eventually select it. The BeginDefaultSelectTimeout
method will be implemented later.
Add the following wait code:
This suspends execution until the player selects an option, the timer expires, or dialogue is cancelled.
Fading it all out
After a selection is made, we need to clean up and exit:
Add the following code:
This cancels the completion source to prevent further selections and disables UI interaction.
Add the following code to fade out the UI:
This fades out the UI and hides all option views, though they remain cached for future use.
Add the following code to return the selected option:
This returns the selected option to the dialogue runner, or indicates that no option was selected if dialogue was cancelled.
Missing Methods
Now we need to implement the methods we've referenced but haven't defined yet:
Add the following new method:
This creates a new option item instance, adds it to the canvas group, positions it at the end of the list, and disables it by default.
Add the
BeginDefaultSelectTimeout
method:
This method initiates the timer bar shrinking animation. When complete (if not cancelled), it sets the designated fallback option as the selected choice.
Drawing the rest of the owl
Finally, let's hook everything up in Unity:
Move back over to Unity and select the Options View in the hierarchy.
Add the
TimeoutOptionsView.cs
script as a new component to the Option View gameobject.Delete the
Options Presenter
component.Select the Options View gameobject and in the Canvas Group field drag the Options View into this field.
From
Packages/Yarn Spinner/Prefabs
folder drag the Option Item prefab into the Option View Prefab field.Drag the timer gameobject into the Timed Bar field.
Pick a duration for the Auto Select, Fade Up, and Fade Down durations.
Now we need to tell the dialogue runner about our custom presenter:
Select the Dialogue System game object in the hierarchy.
Remove the old (now missing) Options Presenter from the Dialogue Views field.
Add the new timeout options view into it's place.
Take it for a spin!
Congratulations! You've created a custom options presenter that supports timed dialogue choices. When the timer expires, the system automatically selects a predefined fallback option, adding a sense of urgency to dialogue interactions.
Last updated
Was this helpful?