Difference between revisions of "Dialogue"

From PowerUI
Jump to: navigation, search
(Created page with "The built in dialogue (speech) system can be used to create conversations between any number of players or 'items' (typically NPCs). It fully supports the localisation system...")
 
(Available properties)
 
(18 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The built in dialogue (speech) system can be used to create conversations between any number of players or 'items' (typically NPCs). It fully supports the localisation system and can be cued from speech playback, synthesis, the player or anything else via scripting. It's also built on top of the window system so dialogue can be easily displayed inside drop-and-go templates.
+
The built in dialogue (speech) system can be used to create conversations between any number of players or 'items' (typically NPCs), or can be used for cutscenes or a sing along. It fully supports the localisation system and can be cued from speech playback, synthesis, the player or anything else via scripting. It's also built on top of the [[Widget Manager|widget system]] so dialogue can be easily displayed inside [[Widget Templates|drop-and-go templates]].
  
 +
== Basic structure ==
  
== Trains of thought ==
+
All dialogue is JSON compatible with PowerSlide. Here's the general structure of those JSON files:
  
Dialogue is represented as a continuous 'train of thought'. Each train is made up of a series of cue cards which describe the dialogue being spoken/ by whom etc. Cue cards and dialogue trains are W3C EventTarget objects, meaning they can send and receive standard events.
+
<syntaxhighlight lang="json">
  
 +
[
 +
  {"speaker":"player"},
 +
  "Hello! My name is &Username;.",
 +
  "All of this text will be said <b>by the player</b>.",
 +
  "It's just an array of text. Because we aren't defining any timing information, it will be cued by the player.",
 +
  "That typically means the player will see something like <i>'press x to continue'</i>.",
 +
 
 +
  {"speaker":"system"},
 +
  "You feel a rush of excitement",
 +
 
 +
  {"speaker":"player"},
 +
  "Ah. That was the system speaker - speaker names can be whatever you want",
 +
  "'system' is reserved as meaning a narrator-style speaker usually present in RPGs.",
 +
  "By convention, spaces are added between speakers, so you can clearly see when a speaker changes."
 +
]
 +
 +
</syntaxhighlight>
 +
 +
Save a file like that in '''Resources/Dialogue'''. For example, ''Resources/Dialogue/myDialogue.json''. To use it, you then use startDialogue:
 +
 +
<syntaxhighlight lang="csharp">
 +
 +
/* Loads myDialogue_en.json with the specified visual template. */
 +
UI.document.startDialogue("myDialogue","templateToUse");
 +
 +
</syntaxhighlight>
 +
 +
For example, call that when a player clicked on an NPC.
 +
 +
As it's PowerSlide, you can also define other tracks in there too (such as a style track and potentially in the future a variety of cutscene management tracks - camera position etc).
 +
 +
== Localisation ==
 +
 +
As seen above with 'Username', localisation variables are fully supported. However, for the purposes of translating all your dialogue, provide multiple versions of the file instead.
 +
 +
''myDialogue_en.json:''
 +
 +
<syntaxhighlight lang="json">
 +
[
 +
  {"speaker":"player"},
 +
  "Hello! My name is &Username;.",
 +
  "All of this text will be said <b>by the player</b>.",
 +
 
 +
  {"speaker":"system"},
 +
  "You feel a rush of excitement"
 +
]
 +
</syntaxhighlight>
 +
 +
''myDialogue_fr.json:''
 +
 +
<syntaxhighlight lang="json">
 +
[
 +
  {"speaker":"player"},
 +
  "Salut! Je m'appelle &Username;.",
 +
  "Tout ce texte sera <b>dit par le joueur</b>.",
 +
 
 +
  {"speaker":"system"},
 +
  "Vous sentez une pointe d'excitation"
 +
]
 +
 +
</syntaxhighlight>
 +
 +
To automatically switch based on the available languages (declared in your languages meta tag) and the UI.Language setting, use {language} in your file path:
 +
 +
<syntaxhighlight lang="csharp">
 +
 +
/* Loads myDialogue_en.json with the specified visual template. */
 +
UI.document.startDialogue("myDialogue_{language}","templateToUse");
 +
 +
</syntaxhighlight>
 +
 +
== Streamed Dialogue ==
 +
 +
If you want to stream it over any of your [[Custom_schema|schemas]], the first argument of startDialogue accepts a complete URL. Use the various PowerSlide start events to catch when it's actually starting up.
 +
 +
<syntaxhighlight lang="csharp">
 +
 +
/* Just use a full URL */
 +
UI.document.startDialogue("cdn://myDialogue.json","templateName");
 +
 +
</syntaxhighlight>
 +
 +
== Further Details ==
 +
 +
Like other PowerSlide tracks, a dialogue track is just a list of slides. If a slide does not define a '''speaker''' then it adopts the speaker applied to the previous slide. If a slide ''only'' defines a speaker, then it's completely ignored from the dialogue stream (but does affect the speaker of the following slides).
 +
 +
So, the first example is short for:
 +
 +
<syntaxhighlight lang="json">
 +
 +
[
 +
  {
 +
    "speaker":"player",
 +
    "markup":"Hello! My name is &Username;."
 +
  },
 +
  {
 +
    "speaker":"player",
 +
    "markup":"All of this text will be said <b>by the player</b>."
 +
  },
 +
  {
 +
    "speaker":"player",
 +
    "markup":"It's just an array of text. Because we aren't defining any timing information, it will be cued by the player."
 +
  },
 +
  {
 +
    "speaker":"player",
 +
    "markup":"That typically means the player will see something like <i>'press x to continue'</i>."
 +
  },
 +
 +
  "etc"
 +
]
 +
</syntaxhighlight>
 +
 +
== Available properties ==
 +
 +
Here's the available properties on dialogue slides.
 +
 +
{| class="wikitable"
 +
|-
 +
! Name
 +
! Description
 +
! Optional
 +
! Example
 +
|-
 +
| speaker or speakers
 +
| The people/ items saying the text.
 +
| Yes, except for the very first slide.
 +
| {"speaker":"joey"}
 +
|-
 +
| markup
 +
| The text to say, as SSML. The 'markup' property is implied if you just have a line of text.
 +
| No, unless speaker/speakers or options is defined.
 +
| "Hello", {"markup":"Hello!"}
 +
|-
 +
| start
 +
| (Same as PowerSlide). The time the dialogue appears at (see the [[#Cutscenes and Timed Dialogue|cutscenes and timed dialogue]] section)
 +
| Yes
 +
| "start":"1.23s"
 +
|-
 +
| duration
 +
| (Same as PowerSlide). How long the dialogue lasts for. If omitted, the slide is cued by the player.
 +
| Yes
 +
| "duration":"1.44s"
 +
|-
 +
| audio
 +
| The URL to an audio file. Usually an ogg in resources, but any of your [[Custom_schema|schemas]] is accepted along with any suitable audio format. Note that PowerSlide will follow the lead of the audio playback engine.
 +
| Yes
 +
| "audio":"myAudioFile.ogg"
 +
|-
 +
| template
 +
| Overrides the visual template to use. Makes it change if needed.
 +
| Yes
 +
| "template":"subtitles"
 +
|-
 +
| options
 +
| Used if the player should pick from one or more options. See more on options below.
 +
| Yes
 +
| "options":[{"markup":"Yes!","goto":".."},{"markup":"No!","goto":".."}]
 +
|-
 +
| wait-for-cue
 +
| Rarely needed. True/false indicates if it should wait for a cue. E.g. if "click to continue" should appear or not.
 +
| Yes. It's true if no duration is declared, or if options are declared. False otherwise.
 +
| "wait-for-cue":"true"
 +
|}
 +
 +
== Speakers ==
 +
 +
Most of the time, speaker information is already available elsewhere. So, PowerSlide does not include a way for storing speaker details (like their name, a chat head etc). Instead, you'll need to provide those details via the PowerSlide.Dialogue.OnGetSpeaker delegate:
 +
 +
<syntaxhighlight lang="csharp">
 +
 +
// using PowerSlide;
 +
 +
Dialogue.OnGetSpeaker=delegate(SpeakerType type,string id){
 +
   
 +
    // Create the speaker object (instance/ return a custom type if you want):
 +
    Speaker speaker=new Speaker(type,id);
 +
   
 +
    /*
 +
        Get the information for whatever type/id refers to now!
 +
   
 +
    e.g:
 +
   
 +
    if(type==SpeakerType.Player && id==null){
 +
       
 +
        // Current player! You can use localisation variables
 +
        // here if you want, or directly set it:
 +
        speaker.fullName="&Username;";
 +
       
 +
    }
 +
   
 +
    */
 +
    // Ok!
 +
    return speaker;
 +
};
 +
 +
</syntaxhighlight>
 +
 +
=== Multiple speakers ===
 +
 +
A single speaker name could represent a group; for example "clan-members" could be ''all'' clan members in the scene. However, if you need to list out multiple speakers, then you simply provide an array like so:
 +
 +
<syntaxhighlight lang="json">
 +
 +
[
 +
  {"speakers":["player","joey"]},
 +
  "STOP!!"
 +
]
 +
 +
</syntaxhighlight>
 +
 +
=== Advanced speakers ===
 +
 +
You might want dialogue between two players in a multiplayer game. The above speaker strings are actually short forms of this:
 +
 +
<syntaxhighlight lang="json">
 +
"speaker":{"type":"player","id":"2"} /* Some remote player */
 +
 +
"speaker":{"type":"player"} /* Current player */
 +
</syntaxhighlight>
 +
 +
== Events ==
 +
 +
Along with all the ordinary widget events and PowerSlide events, dialogue also generates these:
 +
 +
{| class="wikitable"
 +
|-
 +
! Name
 +
! Event object type
 +
! Purpose
 +
|-
 +
| dialoguestart
 +
| PowerSlide.SlideEvent
 +
| Fires when a particular dialogue slide should now be visible.
 +
|-
 +
| dialogueend
 +
| PowerSlide.SlideEvent
 +
| Fires when a particular dialogue slide is no longer visible.
 +
|}
 +
 +
== Mood ==
 +
 +
Mood can change very rapidly throughout dialogue, and can occasionally be hard to translate. Something happy in one culture can actually be upsetting in another, for example. So, mood is declared in the markup as part of SSML - that way it can be translated correctly and is also useful in audio recordings or speech synthesis. See the note about SSML below.
 +
 +
== Cutscenes and Timed Dialogue ==
 +
 +
To make dialogue appear and dissappear at specific times, you simply need to add a '''start''' and optionally a '''duration''' to each entry. Here's an example:
 +
 +
<syntaxhighlight lang="json">
 +
 +
[
 +
  {
 +
    "speaker":"player",
 +
    "start":"0s",
 +
    "duration":"2s",
 +
    "markup":"Hello! My name is &Username;."
 +
  },
 +
  {
 +
    "start":"3s",
 +
    "duration":"3s",
 +
    "markup":"All of this text will be said <b>by the player</b>."
 +
  },
 +
  {
 +
    "start":"7s",
 +
    "duration":"7s",
 +
    "markup":"It's just an array of text. We're defining timing information this time so it won't wait for cues."
 +
  }
 +
]
 +
</syntaxhighlight>
 +
 +
If you don't add a duration it will be set as the time until the following slide (in the same way as all other PowerSlide duration values).
 +
 +
== Sing along ==
 +
 +
Sing alongs typically come in two categories: '''follow the bouncing ball''' and '''style changes''', such as changing the colour of the word/ syllable currently being sung.
 +
 +
The structure of the JSON is the same as [[#Cutscenes and Timed Dialogue|timed dialogue]] except you can optionally add additional per-word or per-syllable timing information. Note that you'll need to use a specific "sing along" dialogue template to make use of that additional timing information and e.g. display a bouncing ball. Here's how that additional timing information is added:
 +
 +
 +
<syntaxhighlight lang="json">
 +
 +
[
 +
  {
 +
    "speaker":"player",
 +
    "start":"0s",
 +
    "duration":"2s",
 +
    "markup":"Hello! My name is &Username;."
 +
  },
 +
  {
 +
    "speaker":"player",
 +
    "start":"3s",
 +
    "duration":"3s",
 +
    "markup":"<cue at='3.1s'>All</cue> <cue at='3.6s'>of</cue> <cue at='3.8s'>this</cue> <cue at='4.2s'>text</cue> <cue at='4.5s'>will</cue> <cue at='4.8s'>be</cue> <cue at='5s'>said</cue> <b><cue at='5.3s'>by</cue> <cue at='5.5s'>the</cue> <cue at='5.7s'>player</cue></b>."
 +
  },
 +
  {
 +
    "speaker":"player",
 +
    "start":"7s",
 +
    "duration":"7s",
 +
    "markup":"It's just an array of text. We're defining timing information this time so it won't wait for cues."
 +
  }
 +
]
 +
</syntaxhighlight>
 +
 +
If you don't add additional timing information then a sing along template is expected to assume a constant speed through the current text.
  
 
== Speech markup language (SSML) ==
 
== Speech markup language (SSML) ==
  
Cue cards contain SSML which may potentially be forwarded to a speech synthesis engine or otherwise checked for mood cues within the speech.
+
All dialogue is actually an extended version of SSML. It can contain all HTML as well as speech hints. It may potentially be forwarded to a speech synthesis engine or otherwise checked for mood cues within the speech.
  
 
<syntaxhighlight lang="html">
 
<syntaxhighlight lang="html">
  
 
<!-- The SSML describes both how it sounds and how it appears on the UI (it fully supports HTML too) -->
 
<!-- The SSML describes both how it sounds and how it appears on the UI (it fully supports HTML too) -->
<happy>Hello &Username; - I'm feeling <i>great</i> today!</happy>
+
<happy>Hello &Username; - I'm feeling <i>great</i> today!</happy> <sad>But..</sad>
  
 
</syntaxhighlight>
 
</syntaxhighlight>
 
== Internal structure ==
 
 
Each train of thought is stored as a JSON file. Automatically generated indices (also JSON) are also created for each dialogue starting point. For example, click/ tapping on an NPC to talk to them will result in all the possible dialogue that starts at that NPC being checked to see which one(s) are most suitable in the current gameplay context. If multiple are suitable then an options menu is created.
 
 
''More information will be coming soon - the API is a work in progress!''
 

Latest revision as of 01:20, 10 May 2017

The built in dialogue (speech) system can be used to create conversations between any number of players or 'items' (typically NPCs), or can be used for cutscenes or a sing along. It fully supports the localisation system and can be cued from speech playback, synthesis, the player or anything else via scripting. It's also built on top of the widget system so dialogue can be easily displayed inside drop-and-go templates.

Basic structure

All dialogue is JSON compatible with PowerSlide. Here's the general structure of those JSON files:

[
  {"speaker":"player"},
  "Hello! My name is &Username;.",
  "All of this text will be said <b>by the player</b>.",
  "It's just an array of text. Because we aren't defining any timing information, it will be cued by the player.",
  "That typically means the player will see something like <i>'press x to continue'</i>.",
  
  {"speaker":"system"},
  "You feel a rush of excitement",
  
  {"speaker":"player"},
  "Ah. That was the system speaker - speaker names can be whatever you want",
  "'system' is reserved as meaning a narrator-style speaker usually present in RPGs.",
  "By convention, spaces are added between speakers, so you can clearly see when a speaker changes."
]

Save a file like that in Resources/Dialogue. For example, Resources/Dialogue/myDialogue.json. To use it, you then use startDialogue:

/* Loads myDialogue_en.json with the specified visual template. */
UI.document.startDialogue("myDialogue","templateToUse");

For example, call that when a player clicked on an NPC.

As it's PowerSlide, you can also define other tracks in there too (such as a style track and potentially in the future a variety of cutscene management tracks - camera position etc).

Localisation

As seen above with 'Username', localisation variables are fully supported. However, for the purposes of translating all your dialogue, provide multiple versions of the file instead.

myDialogue_en.json:

[
  {"speaker":"player"},
  "Hello! My name is &Username;.",
  "All of this text will be said <b>by the player</b>.",
  
  {"speaker":"system"},
  "You feel a rush of excitement"
]

myDialogue_fr.json:

[
  {"speaker":"player"},
  "Salut! Je m'appelle &Username;.",
  "Tout ce texte sera <b>dit par le joueur</b>.",
  
  {"speaker":"system"},
  "Vous sentez une pointe d'excitation"
]

To automatically switch based on the available languages (declared in your languages meta tag) and the UI.Language setting, use {language} in your file path:

/* Loads myDialogue_en.json with the specified visual template. */
UI.document.startDialogue("myDialogue_{language}","templateToUse");

Streamed Dialogue

If you want to stream it over any of your schemas, the first argument of startDialogue accepts a complete URL. Use the various PowerSlide start events to catch when it's actually starting up.

/* Just use a full URL */
UI.document.startDialogue("cdn://myDialogue.json","templateName");

Further Details

Like other PowerSlide tracks, a dialogue track is just a list of slides. If a slide does not define a speaker then it adopts the speaker applied to the previous slide. If a slide only defines a speaker, then it's completely ignored from the dialogue stream (but does affect the speaker of the following slides).

So, the first example is short for:

[
  {
    "speaker":"player",
    "markup":"Hello! My name is &Username;."
  },
  {
    "speaker":"player",
    "markup":"All of this text will be said <b>by the player</b>."
  },
  {
    "speaker":"player",
    "markup":"It's just an array of text. Because we aren't defining any timing information, it will be cued by the player."
  },
  {
    "speaker":"player",
    "markup":"That typically means the player will see something like <i>'press x to continue'</i>."
  },

  "etc"
]

Available properties

Here's the available properties on dialogue slides.

Name Description Optional Example
speaker or speakers The people/ items saying the text. Yes, except for the very first slide. {"speaker":"joey"}
markup The text to say, as SSML. The 'markup' property is implied if you just have a line of text. No, unless speaker/speakers or options is defined. "Hello", {"markup":"Hello!"}
start (Same as PowerSlide). The time the dialogue appears at (see the cutscenes and timed dialogue section) Yes "start":"1.23s"
duration (Same as PowerSlide). How long the dialogue lasts for. If omitted, the slide is cued by the player. Yes "duration":"1.44s"
audio The URL to an audio file. Usually an ogg in resources, but any of your schemas is accepted along with any suitable audio format. Note that PowerSlide will follow the lead of the audio playback engine. Yes "audio":"myAudioFile.ogg"
template Overrides the visual template to use. Makes it change if needed. Yes "template":"subtitles"
options Used if the player should pick from one or more options. See more on options below. Yes "options":[{"markup":"Yes!","goto":".."},{"markup":"No!","goto":".."}]
wait-for-cue Rarely needed. True/false indicates if it should wait for a cue. E.g. if "click to continue" should appear or not. Yes. It's true if no duration is declared, or if options are declared. False otherwise. "wait-for-cue":"true"

Speakers

Most of the time, speaker information is already available elsewhere. So, PowerSlide does not include a way for storing speaker details (like their name, a chat head etc). Instead, you'll need to provide those details via the PowerSlide.Dialogue.OnGetSpeaker delegate:

// using PowerSlide;

Dialogue.OnGetSpeaker=delegate(SpeakerType type,string id){
    
    // Create the speaker object (instance/ return a custom type if you want):
    Speaker speaker=new Speaker(type,id);
    
    /* 
        Get the information for whatever type/id refers to now!
    
    e.g:
    
    if(type==SpeakerType.Player && id==null){
        
        // Current player! You can use localisation variables 
        // here if you want, or directly set it:
        speaker.fullName="&Username;";
        
    }
    
    */
    // Ok!
    return speaker;
};

Multiple speakers

A single speaker name could represent a group; for example "clan-members" could be all clan members in the scene. However, if you need to list out multiple speakers, then you simply provide an array like so:

[
   {"speakers":["player","joey"]},
   "STOP!!"
]

Advanced speakers

You might want dialogue between two players in a multiplayer game. The above speaker strings are actually short forms of this:

"speaker":{"type":"player","id":"2"} /* Some remote player */

"speaker":{"type":"player"} /* Current player */

Events

Along with all the ordinary widget events and PowerSlide events, dialogue also generates these:

Name Event object type Purpose
dialoguestart PowerSlide.SlideEvent Fires when a particular dialogue slide should now be visible.
dialogueend PowerSlide.SlideEvent Fires when a particular dialogue slide is no longer visible.

Mood

Mood can change very rapidly throughout dialogue, and can occasionally be hard to translate. Something happy in one culture can actually be upsetting in another, for example. So, mood is declared in the markup as part of SSML - that way it can be translated correctly and is also useful in audio recordings or speech synthesis. See the note about SSML below.

Cutscenes and Timed Dialogue

To make dialogue appear and dissappear at specific times, you simply need to add a start and optionally a duration to each entry. Here's an example:

[
  {
    "speaker":"player",
    "start":"0s",
    "duration":"2s",
    "markup":"Hello! My name is &Username;."
  },
  {
    "start":"3s",
    "duration":"3s",
    "markup":"All of this text will be said <b>by the player</b>."
  },
  {
    "start":"7s",
    "duration":"7s",
    "markup":"It's just an array of text. We're defining timing information this time so it won't wait for cues."
  }
]

If you don't add a duration it will be set as the time until the following slide (in the same way as all other PowerSlide duration values).

Sing along

Sing alongs typically come in two categories: follow the bouncing ball and style changes, such as changing the colour of the word/ syllable currently being sung.

The structure of the JSON is the same as timed dialogue except you can optionally add additional per-word or per-syllable timing information. Note that you'll need to use a specific "sing along" dialogue template to make use of that additional timing information and e.g. display a bouncing ball. Here's how that additional timing information is added:


[
  {
    "speaker":"player",
    "start":"0s",
    "duration":"2s",
    "markup":"Hello! My name is &Username;."
  },
  {
    "speaker":"player",
    "start":"3s",
    "duration":"3s",
    "markup":"<cue at='3.1s'>All</cue> <cue at='3.6s'>of</cue> <cue at='3.8s'>this</cue> <cue at='4.2s'>text</cue> <cue at='4.5s'>will</cue> <cue at='4.8s'>be</cue> <cue at='5s'>said</cue> <b><cue at='5.3s'>by</cue> <cue at='5.5s'>the</cue> <cue at='5.7s'>player</cue></b>."
  },
  {
    "speaker":"player",
    "start":"7s",
    "duration":"7s",
    "markup":"It's just an array of text. We're defining timing information this time so it won't wait for cues."
  }
]

If you don't add additional timing information then a sing along template is expected to assume a constant speed through the current text.

Speech markup language (SSML)

All dialogue is actually an extended version of SSML. It can contain all HTML as well as speech hints. It may potentially be forwarded to a speech synthesis engine or otherwise checked for mood cues within the speech.

<!-- The SSML describes both how it sounds and how it appears on the UI (it fully supports HTML too) -->
<happy>Hello &Username; - I'm feeling <i>great</i> today!</happy> <sad>But..</sad>