-
Notifications
You must be signed in to change notification settings - Fork 183
Adding Story Mode Content
Story mode is a minigame where the main focus lies on telling a story about little Mario. It features gameplay elements like talking to characters in the world, exploring, collecting items and solving puzzles.
Items can be given by characters or collected from the ground. They can be viewed inside the inventory by pressing [E]
.
To add a new item, create a new resource of type StoryItem
and put it inside the content/items
folder.
Inside the resource you can change the name, description and texture of the item.
To add the item to the world you can use the GroundItem
scene. Instantiate it inside the level under the Items
node, move it to the right place and drag the item resource into the item
property.
Characters, or NPCs, are persons or objects that can be interacted with.
To add a new character type, create a resource of type StoryCharacterData
in the content/characters
folder.
You can configure the name and texture of the character.
To place this character inside the world, instantiate a Character
scene and drag the character into the data
property.
Each character can have a dialog you can trigger, and a text that is displayed if you can talk to them. You should also right click the scene and enable Editable Children
. Then you can position the label, collision shape and sprite where they make sense. To make sure the YSort works, position the bottom of the sprite at the origin point of the character.
Dialogs are written in JSON files. To get the best editing experience you should use an IDE with JSON schema validation, like VSCode or Vim.
To start, create a new JSON file inside content/dialogs
with this template:
{
"$schema": "schema/dialog.schema.json",
"text": "I am learning about how to create dialogs!",
"choices": [
"That's awesome!",
{
"text": "Good luck!",
"dialog": "Thanks!"
}
]
}
The $schema
tells your IDE that you are writting JSON with a specific structure. It will give you errors, hints and tooltips.
The text
can be a string or a list of strings, and is the message the character says to the player.
Choices can be a list of responses the player can choose.
To make the dialog appear in the game you need to assign it to a character or start it inside a script like this:
# Get a reference to the dialog UI.
var dialog_ui = $CanvasLayer/UI/DialogUI
# Start the "shop" dialog. `character` is optional.
dialog_ui.start(preload("shop.json"), character)
If you want an animation to play during a dialog, add it to the CutScenePlayer
animation player. To trigger the cutscene, add an event
property with the same name as the animation. The dialog will resume after the animation is done playing.
Hubs are a common pattern inside dialog-based games. They provide a dialog message you can return to after completing branches inside a dialog. This can be achieved using the goto
property.
Example:
{
"$schema": "schema/dialog.schema.json",
"text": "What do you want to know?",
"label": "start",
"choices": [
{
"text": "What is two plus two?",
"dialog": {
"text": "Uhmm.... That would be.... four?",
"choices": [
{
"text": "One more thing...",
"dialog": {
"goto": "start"
}
}
]
}
},
{
"text": "What is two divided by zero?",
"dialog": {
"text": "Uhhmm... I think that's NaN?",
"choices": [
{
"text": "One more thing...",
"dialog": {
"goto": "start"
}
}
]
}
},
"Bye!"
]
}
To get the dialogs to interact with GDScript you can use events. When an event is hit the dialog UI will emit an event_occured
signal.
Example:
{
"$schema": "schema/dialog.schema.json",
"text": "This looks like a button.",
"choices": [
{
"text": "Press it.",
"dialog": {
"text": "Nothing happens.",
"event": "clicked_button"
}
}
]
}
You can give the players items after a dialog has finished.
The name should be the file name of the item data resource without extension.
Example:
{
"$schema": "schema/dialog.schema.json",
"text": "A pie.",
"choices": [
{
"text": "Take it.",
"dialog": {
"text": "You take the pie. It looks delicious.",
"item": "pie"
}
}
]
}
Often times it is necessary to have multiple dialogs speak in one conversation. You can do so by chaining dialogs together and setting the character
property:
{
"$schema": "schema/dialog.schema.json",
"text": "I am the original speaker!",
"next": [
{
"text": ["I AM THE SECOND SPEAKER!"],
"character": "wizard_dude"
},
{
"text": "i am the third speaker",
"character": "donk"
}
]
}
Conditions can be used inside dialogs or conditions to create branching dialogs.
Example of conditional choices:
{
"$schema": "schema/dialog.schema.json",
"text": "Have we met before?",
"choices": [
{
"condition": {
"custom": "have_met",
"inverted": true
},
"text": "I don't think so.",
"dialog": "Greetings then!"
{
"condition": {
"custom": "have_met"
},
"text": "Yes, we have.",
"dialog": "Nice to see you again!"
},
{
"condition": {
"item": "pie"
},
"text": "Here, have this pie! I'm sadly allergic to it",
"dialog": "Thank you!"
}
],
"event": "met_guy"
}
Example using true/false:
{
"$schema": "schema/dialog.schema.json",
"condition": {
"custom": "is_rich"
},
"true": {
"text": "You have a lot of coins!"
},
"false": {
"text": "You Are poor!"
}
}
When you set the field custom
, the method with the same name will be executed on the main story mode script. The condition is only true if the method returned true.
If it doesn't make sense that the player reaches the same dialog twice you can use the occurence
number:
{
"$schema": "schema/dialog.schema.json",
"text": "Have we met before?",
"choices": [
"Maybe...",
{
"text": "No, this is the first time!.",
"condition": {
"occurence": 1
}
}
]