Cutscene sequences are defined in simple, text-based commands. Since they're text, these sequences are very compact, and they're quick and easy for dialogue authors to add as they write dialogue, even in external authoring programs such as Chat Mapper and articy:draft. A large library of sequencer commands is already included, and you can easily add your own.
To jump right in, you can skip down to Simple Example: Audio.
If you don't want to specify your sequences in text strings, you can use a scrubbing sequence editor such as Well Fired's uSequencer and simply call the uSequencer sequence by using the provided uSeq() command.
The format of a sequencer command make look intimidating at first, but don't worry! It boils down to a couple very simple patterns. You'll get the hang of it very quickly.
The general format of a sequencer command is:
[required
] command (
[parameters] )
[@
seconds]
or:
[required
] command (
[parameters] )
[@Message(
message)
]
(The square brackets around parts such as required
mean it's optional.)
You can also add this optional part to the end:
->Message(
endmessage)
The parts mean:
Part | Description |
---|---|
required | This optional keyword specifies that the command must run even if the player cancels the sequence |
command | The command to play (e.g., "Camera" in Camera(Closeup) ) |
parameters | The parameters for the command (e.g,. "Closeup" in Camera(Closeup) ) |
@ seconds | The optional time at which to play the command; otherwise it plays immediately |
@Message( message) | The message to wait for before playing the command; otherwise it plays immediately |
->Message( endmessage) | A message to send to the sequencer when the command completes |
The following keywords are available as parameters in dialogue entries:
Keyword | Description |
---|---|
speaker | The actor in the current dialogue entry, or the assigned speaker in a non-conversation sequence |
listener | The conversant in the current dialogue entry, or the assigned listener in a non-conversation sequence |
entrytag | A unique identifier for a dialogue entry (see How to Use Entrytags or How to Add Lipsync for example use) |
entrytaglocal | The dialogue entry's localized entrytag for the current language |
{{end}} | A numeric value based on the length of the current dialogue entry's subtitle text |
{{default}} | Gets replaced with the Dialogue Manager's Default Sequence. Use this to include the Default Sequence in your dialogue entries' custom sequences |
Certain commands also have special, command-specific keywords, too. Those keywords are described in the documentation for the command.
Example:
You can register your own shortcuts using a Sequencer Shortcuts component or the Sequencer.RegisterShortcut method. A shortcut is a string that's an alias for one or more sequencer commands. If you include the shortcut in a sequence, wrapped in double-braces, it will be replaced by its sequencer commands.
Keyword | Description |
---|---|
{{ shortcut}} | Replaced by the shortcut's value |
Example:
Sequence:
Sequences may also contain [var=
varName]
and [lua(
code)]
markup tags. For more information about markup tags, see Dialogue Markup Tags.
Example:
Very often the player is already assigned as the speaker of the conversation or sequence. In this case, you can use the special keyword 'speaker' to refer to the player even if its name does have parentheses:
LookAt(speaker)
If the sequence runs during an NPC line, the player may be 'listener' in this case.
Fade(in) Camera(Closeup, listener) Animation(jump)@2.5 AudioWait(whisper)->Message(AllDone) required AnimatorPlay(idle)@Message(AllDone)
(sequencer code above)
String together multiple commands by putting a semicolon (;
) between them:
Audio(waltz); Animation(dance); required Animation(idle)@2
(sequencer code above)
Here's a simple example of adding audio to your conversations:
Resources
(use exact spelling and capitalization) in your project. You can have any number of Resources
folders in your project anywhere under Assets
.Resources
folder. You can optionally organize them under subfolders. For example, let's say you've created a subfolder under Resources
named Adam
, and you've put an audio file hello.mp3
in this subfolder.In your conversation's dialogue entry, set the Sequence field to:
AudioWait(Adam/hello)
<code><pre>AudioWait(Adam/hello, Loudspeaker)</pre></code>
Commands are not sequential. Every command will try to run at the start of the sequence unless it uses the @
seconds or @Message(
message)
. If you use either of these two syntaxes, the command will wait in a queue until the condition is met (i.e., the time mark has arrived, or the sequencer received the specified message).
In addition, many commands will start some kind of activity in Unity and then exit, leaving the activity running in the background.
For example, the Audio()
command will start an audio clip playing on an audio source and then exit immediately. These commands usually have an equivalent command that will wait until the activity is done. For audio, the AudioWait()
command waits until the audio clip is done before exiting.
A sequence is not done until all of its commands are done. The duration of the sequence Audio(whisper)
is 0 seconds. The duration of AudioWait(whisper)
is the length of the audio clip whisper
.
This is an example fight sequence involving animation, sound, and camera work.
Camera(Closeup); Animation(Punch); Camera(Wide,listener,1)@2; Audio(Oof,listener)@2.5; required Animation(Crumple,listener)@2.5
The sequence does this:
Note that we specified that the crumple animation is required; this ensures that the listener ends up in the correct position (crumpled on the ground) even if the player cancels (skips) the cutscene. Very often, the last Camera()
command in a sequence will be marked required
to make sure the camera is set up for the next line of dialogue.
This example uses the @Message()
syntax to keep a command queued until the sequencer receives a message.
SendMessage(Bomb, StartCountdown); SetActive(Bomb, false)@Message(Kaboom); SetActive(Explosion)@Message(Kaboom)
(sequencer code above)
The sequence does this:
StartCountdown()
that counts down and then sends the message "Kaboom" as shown in the code below.You could use this script on Bomb:
(C# code above)
Note that the CountDownAndExplode()
method above uses a static method Sequencer.Message()
to send a message to the sequencer(s) on the Dialogue Manager GameObject.
This example uses the ->Message()
syntax, which sends a message when a command completes, and the @Message()
syntax, which waits until the sequencer receives a message.
Animation(Punch)->Message(Punched); required Animation(Crumple,listener)@Message(Punched)
(sequencer code above)
The sequence above plays the speaker's Punch animation. At the end of the animation, it sends the message "Punched" to the sequencer.
The second Animation()
command is configured to wait for the "Punched" message. When it receives this message, it plays the listener's Crumple animation.
If you use Unity Pro/Unity 5+ and Asset Bundles, your sequences can load assets from asset bundles in addition to Resources folders. You must first register your loaded asset bundles with the Dialogue System using PixelCrushers.DialogueSystem.DialogueManager.RegisterAssetBundle.
The following code registers an asset bundle with the Dialogue System, then runs a sequence to play an audio clip named "alarmSound" through a GameObject named "Loudspeaker". The Dialogue System will attempt to load "alarmSound" from all registered asset bundles, then from Resources folders.
(C# code above)
Before freeing a registered asset bundle, make sure to unregister it from the Dialogue System:
(C# code above)
<< Sequences | Sequencer Command Reference >>