A huge topic in game and multimedia app development is good and none-redundant dialogue or conversation management. With Gorilla3D you have an easy-to-use component which is also able to handle complex conversations.
- Complex & flexible design in tree structure
- (Un)lockable items
- Crosslinking of items possible
- Question and Answer/Option model
- Display-Time and Timeout configuration
- Design of dialogues & monologues with colloquist information
- Multilingual system easily definable
- Auto-language selection
- Set variables to implement gaming elements
- Set parameters to interact back with your game/application
- Events for: showing text and images, playing audio, video and animations, executing method calls, property settings, redirection & more
- Events with different scopes: dialogue item, UI-element, gaming element
- Pause, stop and skip dialogues and items
- Storable as single or multiple dialogue files/streams (dynamic loading possible)
- Storeable in xml format
- Loadable from xml file/stream
- Readable and understandable xml format, to outsource design & management of dialogues.
- Fully customizable in Delphi
We already built a helper tool for you to setup dialogues by a flow chart editor.
- Create dialogues, items and events simply by drag & drop
- Move, rearrange and delete items & events
- Configure every dialogue, item and event in detail
- Treeview for easy dialogue navigation
- Preview dialogues in sandbox viewer
The dialogue system is the basis component for setting up and manage multiple dialogues/conversations and variables. Imagine the dialogue system as a hierarchy, which is able to jump between leaves (items) and execute events, to playback animations, sounds or execute scripts:
- Characters (conversation partner)
- Items (Textfragments of conversation)
- Events (do something)
To start setting up a system, a few properties are important to know:
|Id||Unique id for a specific dialogue system. On creation automatically a random id will be generated, but it's possible that this id is not unique. The user should take care, that this id is unique!|
|Language||Defines the currently used language by id. This property affects auto language map handling for items and events. Dialogue Designer uses ISO language id's, like “en-us”, “de-de”, …|
|Dialogues||A collection of available dialogue instances.|
|Variables||A hashmap of <name>,<TObject> pairs. Register variables to connect another environment with the dialogue system.|
Simply set up a dialogue system at runtime like in the following code snippet:
uses Gorilla.Utils.Dialogue.System; [...] FDialogueSys : TGorillaDialogueSystem; FDialogue : TGorillaDialogue; [...] // create a dialogue system on our form (its a none-visual component) FDialogueSys := TGorillaDialogueSystem.Create(Self); // create a new dialogue FDialogue := FDialogueSys.Dialogues.Add() as TGorillaDialogue;
Because the dialogue system is a logical component without any visual or game interactive feedback, you have to use a visual UI framework on top. We provide a simple one for you in the Gorilla.UI.Dialogue.Overlay or by the Gorilla.UI.Dialogue.Sandbox unit.
All UI interfaces for a dialogue system bind its callback event to display text, playback audio or whatever.
|OnBeginDialogueItemEvent||Callback event gets called when an item event gets executed.|
|OnEndDialogueItemEvent||Callback event gets called when an item event gets stopped.|
|OnBeginDialogueItem||Callback event gets called when an item is going to be displayed.|
|OnEndDialogueItem||Callback event gets called when an item is going to be hidden.|
|OnStartDialogue||Callback event gets called when a specific dialogue was started.|
|OnStopDialogue||Callback event gets called when a specific dialogue was stopped.|
|OnPauseDialogue||Callback event gets called when a specific dialogue was paused.|
|OnSkippedDialogue||Callback event gets called when a specific dialogue was skipped by user interaction.|
|OnSkipAvailability||Callback event gets called on start of a specific item. The callback submits if a skip is available for this specific item. Use this event to display a skip button only when skipping is allowed.|
|OnBeginItemTimeout||Callback event gets called on dialogue item start, when a display time is set. The callback is called before event execution.|
|OnEndItemTimeout||Callback event gets called on execution timeout in the DoOnExecTimerEvent() routine. The callback is called before timeout events execution.|
uses Gorilla.UI.Dialogue.Overlay; [...] FHUD := TGorillaDialogueHUD.Create(Self); FHUD.Parent := Self; FHUD.Align := TAlignLayout.Client; FHUD.Viewport := GorillaViewport1; FHUD.AudioManager := GorillaAudioManager1; FHUD.Dialogue := FDialogue; [...] FHUD.Start();
A TGorillaDialogue instance is a single closed conversation. So if you want to have a dialogue between character A and B this is the point to start. A TGorillaDialogue manages items and characters. An item can be seen as a text-fragment in your conversation but is much more. A character is a helper structure to organize your conversation. Because it's always important to know who is speaking. Besides this simple fact, a character is used as variable, which can be accessed.
As you've seen above, you add a new dialogue by adding a collection item in the TGorillaDialogueSystem.Dialogues collection. In the next step we should add two characters for our conversation partners, which is also done by adding a collection item. You can of course add more than 2 characters, but to keep it simple, we'll stay here with A and B.
FCharacterA := FDialogue.Characters.Add() as TGorillaDialogueCharacter; FCharacterA.Name := 'A'; FCharacterB := FDialogue.Characters.Add() as TGorillaDialogueCharacter; FCharacterB.Name := 'B';
Once you've done that, we can start adding our text fragments.
A text fragment is an entity representing a snippet of a conversation or monologue. In most cases its a phrase, a sentance or longer text passage spoken by a single character. So the main duty for setting up a conversation is to split it up the complete text into parts or so called items.
A TGorillaDialogue and a TGorillaDialogueItem are both inherited from TGorillaDialogueParentItem, which is able to hold further sub-items. So you can to setup a hierarchy, that represents a text playback order automatically.
Dialogue "Hello World!" "How are you?" "I'm fine"
The example above will playback the text fragments in order:
- “Hello World”
- “How are you?”
- “I'm fine”
Each item also has the possibility to register events to control the text flow. Those events allow the dialogue system to handle even complex conversation flow. What events can do for you, you can read further below.
|Kind||Currently the following item kinds are supported: Question, Answer, Flow, Reference|
|DisplayName||This value should be unique, but is managed by the user|
|Character||Defines a linked character. If DisplayName is not set, but a character is defined, the component will return the characters name as display name.|
|Reference||In case the kind is set to TGorillaDialogueItemKind.Reference, this property needs to be set to the DisplayName of the linked item.|
|DisplayTime||Defines a time, for how long an item is going to be displayed, before it gets automtically skipped by the system.|
|Text||The hashmap is a list of «language-id>,<text» pairs. The hashmap is a list of «language-id>,<text» pairs. Use the GetCurrentText() method to request the currently translated text content, depending on the dialogue system language setting.|
|Events||Returns a collection of item events.|
Kinds of items
A dialogue seldomly is just a text flow. You nearly always will have questions, answers to choose from or points to which to return to. Our dialogue system allows to configure those variations easily.
|TGorillaDialogueItemKind.None||undefined kind - should never be set|
|TGorillaDialogueItemKind.Question||A text-fragment marked as question. This will load up sub-items as possible answers to choose from.|
|TGorillaDialogueItemKind.Answer||Text-fragments marked as possible options to choose from. The parent item should be a question item.|
|TGorillaDialogueItemKind.Flow||A default text-fragment, simply plays back for a defined timespan and then switches to the next item in row|
|TGorillaDialogueItemKind.Reference||A reference item is used as dummy fragment to forward to another item. Use this to jump at specific text-fragments in your dialogue. For example if you want to reask a question.|
Events in items allow interaction with your game and to control the text flow of the conversation.
LItem : TGorillaDialogueItem; LEvent : TGorillaDialogueItemEvent; [...] LEvent := LItem.Events.Add() as TGorillaDialogueItemEvent; LEvent.Kind := TGorillaDialogueEventKind.Text; LEvent.Trigger := TGorillaDialogueEventTrigger.OnBegin;
A few configuration properties allowing you to setup an event for many purposes:
|OwnerEvent||It is possible to execute events by another event. For example for animations, where you have a starting and finish event.|
|Kind||Defines the kind of event. Supported types are: Text, Image, Audio, Video, Animation, Method, ObjProperty, Redirect, Timer, Misc|
|Trigger||Defines the moment of event execution. Supported types are: OnBegin, OnEnd, OnTimeout|
|Scope||A scope should be a component name or a dialogue item ident. Which value to be used depends on the kind of event. Use “ui” to work on the linked UIElement of the current dialogue item. Use “self” to work on the current event. It's possible to use variable names here or different item id's.|
|Data||Defines the multilingual data container. Use this property to define language specific texts, f.e. for displaying a text event.|
|Iterations||If the property is set to zero, functionality is disabled. Values larger than zero, perform iteration checks inside Execute() method. For example: Value=3, the event will be called only if the item was played back 3 times.|
Kind of events
The system distinguishes between internally managed events and user specific events. Internally handled events can not be influenced by the UI. But user-specific events will only be handled by the user interface.
|TGorillaDialogueEventKind.Text||User-Specific||intended to show a text on screen|
|TGorillaDialogueEventKind.Image||User-Specific||intended to show an image on screen|
|TGorillaDialogueEventKind.Audio||User-Specific||intended to playback an audio file|
|TGorillaDialogueEventKind.Video||User-Specific||intended to playback a video file|
|TGorillaDialogueEventKind.Animation||User-Specific||intended to start a model animation or a TAnimation instance|
|TGorillaDialogueEventKind.Method||Internal||executes a published method by RTTI|
|TGorillaDialogueEventKind.ObjProperty||Internal||sets a specific property|
|TGorillaDialogueEventKind.Redirect||Internal||redirects to another item|
|TGorillaDialogueEventKind.Timer||User-Specific||starts timeout counter and allows to run another event|
|TGorillaDialogueEventKind.Misc||User-Specific||intended to use for individual purposes|
The data value used depends on the kind of event. While for text, image, audio or video a language specific data value is important, the data value for method or object-properties is generally valid.
Example for adding multilingual sound files:
LEvent.Kind := TGorillaDialogueEventKind.Audio; LEvent.Data.AddOrSetValue('en-us', 'flash_en-us.mp3'); LEvent.Data.AddOrSetValue('de-de', 'flash_de-de.mp3');
Example for adding generally available texts, by using “*” as language key:
LEvent.Kind := TGorillaDialogueEventKind.Text; LEvent.Data.AddOrSetValue('*', 'a b c d e f');
Example for setting an object property. Here a disabled flow-item will be enabled by an event.
LEvent.Kind := TGorillaDialogueEventKind.ObjProperty; // scope is the item to change property defined in "Paramaters" LEvent.Scope := 'Question1_Answer2_FlowItem3'; LEvent.Parameters.AddOrSetValue('Enabled', TValue.From<Boolean>(true));
Load & Save
The dialogue system supports loading and storing conversations to file (*.dia;*.dlg). The AssetsManager also supports this file format, so you can push those files to your game package.
FDialogueSys := TGorillaDialogueSystem.Create(Self); FDialogueSys.LoadFromFile('MyDialogues.dia');
To store your dialogue settings, simply call SaveToFile or SaveToStream.
Next step: SkillSystem