I first want to make it known that I will not buy or download any assets. I want to learn how to do things myself rather than taking the easy way out.
To reiterate the title of this thread, What is the best way to create a dialogue system? I am not looking for anything fancy with a ton of customization. I just want to know the best way to structure classic JRPG dialogue.
This style generally consists of a picture for each participating character, Dialogue options that can branch out into different dialogue segments, and a sound that plays whenever a characters starts talking(usually a âgaspâ or âhuhâ sound to react to the previous characters dialogue).
Example:
Just scripting this is half of my battle. I also need a way to allow someone who has never coded in their life to easily create new dialogue trees.
Currently I have 2 ideas for this but I doubt they are efficient or easy to pull off.
Scriptable Objects: I am not quite sure how to go about this but it would make exposing variables easy but also tedious to fill in.
Custom node editor: I know this is a bit ambitious but it would be worth it in the long run. I have very little experience with custom inspectors, but if there is an expert out there who is willing to put up with my idiocy, I believe this would be the best option.
Any help on where to start and/or structure is greatly appreciated.
We are using a custom text parser, so if I want bold text for example I have bold text tags, ect. So each character gets its own txt file.
The text parser also includes speed indicators and emote tags. As an example.
As I said, each character gets its own text file, we also have âpartsâ in it. So there is an indicator like &1&, that indicates that if we pass along â1â as the dialogue number, it will only read from part 1.
I plan on adding a &*r& tag as well, so when the player exhaust a part, and hasnât moved on to the next part, they will hit that repeat tag in that part.
[e0][e1][s1] Hello!
This means, eyes emotion 0, mouth emotion 1, print speed 1. We can change those any time by dropping those tags in. We have 7 standard emotions for the eyes and mouth, and then three custom additional slots.
We are using using game objects for each letter, and loading a âfontâ in which is actually a class for slots for each letter. This lets us apply shaders, jiggle, or even use letters as game objects. Just anything we want to do.
Itâs wise of you to be thinking of this from the start. I have a bit of experience with dialogue systems, and the two things that devs spend the most time on are authoring and UI.
Authoring involves providing an editing environment for non-programmers and a fast, simple workflow to convert their content into a data model that your dialogue system can work. You can get a no-frills custom editor up and running pretty quickly in Unity, but as you add features it can become a large project unto itself. Consider leveraging an existing editor such as Twine or articy:draft. Talk with your writer(s) and ask them if they have any preferred tools. If theyâre modders, maybe theyâre already comfortable with the Neverwinter Nights or Dragon Age toolsets (which can export to a simple XML format) and can be productive right away.
Then you just need to write a importer that can convert it to your data model. When youâre designing your data model, try to think of features that youâll need, such as language localization, and how this will impact the authorâs workflow. If you end up using translators, youâll need a way to get content into and out of Unity, since translators generally work with tools like MS Excel, not Unity. Think about workflow here, too. The more you can offload on the writers, the happier everyone will be. The writers will have more creative control, and the projectâs workload will be better balanced so everyoneâs not constantly waiting on you to write code. Even if you write an editor in Unity, youâll probably still need a way to get content into and out of Unity.
The UI part is also deceptively complex. Depending on your build platforms, you may need to support joystick navigation, touch input, different resolutions, etc. A lot of JRPGs employ a typewriter-style effect that also allows the writer to specify pauses and other timing codes in their text. (This is more common in visual novels, but still used frequently in JRPGs.) The writers will probably also want control over changing charactersâ pictures, either on a permanent basis (e.g., an NPC gets a permanent scar) or temporary (the NPC has an angry expression for part of a conversation).
Actually yeah, do you want code, or do you just mean in general? If youâve never coded, start with just using the UI, and programatically changing the text.
To clarify, string parsing is when you start working with strings to change things. For example, in this case, I replace ** with a bold text marker and then replace ** with an end bold text marker. This requires me to keep count of start and end markers. You can do it however you want. So when the parser hits [e0][e1] it doesnât print that. Instead, it remove it from the string, and sets the emotes.
Currently I am trying to create a system that will read, format, and print lines of Dialogue from a text file. Everything works until I try to switch to the next line. I keep getting a vague error that wont even point me to the line of code that is causing the problem.
I have also noticed that the script does not print only 10 characters per line like it should. I assume that this is also part of the problem. EDIT I counted and each line displays 10 more characters than the last
Full Script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class DialogueReader : MonoBehaviour {
//private List<BaseCharacterAsset> CharacterAssests = new List<BaseCharacterAsset>();
public TextAsset Dialogue;
private int currentLine; //Line in text file
private int currentChar; //current Character in the line
private int lineLimit = 10; //# of characters in a textbox line before moving to the next line
void LoadResources()
{
//CharacterAssests.Clear();
//BaseCharacterAsset[] resources = Resources.LoadAll<BaseCharacterAsset>(@"CharacterDialogueAssets");
//foreach (BaseCharacterAsset characterAsset in resources)
//{
// CharacterAssests.Add(characterAsset);
//}
}
private string[] allLines;//array of each line in the text file
private int lineLength;//length of the current line
void ReadLine()
{
//Debug.Log("Hello?");
if (currentChar == lineLength)
{
//Debug.Log("Hello?");
NextLine();
}
//Debug.Log("Hello?");
Debug.Log(lineLength);
Debug.Log(currentChar);
if (currentChar + lineLimit >= lineLength) { rawSubstring = allLines[currentLine].Substring(currentChar, currentChar + lineLimit); currentChar = lineLength; }
else { rawSubstring = allLines[currentLine].Substring(currentChar, currentChar + lineLimit); currentChar += lineLimit; }
FormatSubString();
Debug.Log(formattedSubString);
}
string rawSubstring;//before formatting
string formattedSubString;//after formatting
void FormatSubString()
{
if (rawSubstring.StartsWith(" "))
{
rawSubstring.Remove(0);
}
formattedSubString = rawSubstring;
}
void NextLine()
{
currentChar = 0;
if (allLines[currentLine + 1] != "")
{
Debug.Log("Passes");
currentLine++;
}else{
EndDialogue();
}
lineLength = allLines[currentLine].Length;
}
void CompileLines()
{
currentLine = 0;
currentChar = 0;
allLines = File.ReadAllLines(Dialogue.name.ToString() + ".txt"); //Still Trying to figure this part out. put file in first level of project folder
for (int i = 0; i < allLines.Length; i++)
{ Debug.Log(allLines[i]); }
lineLength = allLines[currentLine].Length;
}
void EndDialogue()
{
Debug.Log("End");
}
private void Start()
{
CompileLines();
}
public void Next()
{
ReadLine();
}
}
I have also attached the text document I am using for testing.
As stated before any and all help is very much appreciated.
It looks like you are out of the bounds of the string array. Strings are just arrays of chars. Sorry if this is way off, I canât test anything since I at work.
I misread the parameters. the substring method needed a Start position and a length. I thought it said a Start Position and an End Position. Everything works perfectly now.
currently I have set it up to create 2 different versions of each line. The first is the raw form with with all of my tags. The second is a version stripped of all of the tags. I then have it reading and printing from the stripped version because I do not want the tags to be included in the character count. I now need to figure out how to compare the raw and the stripped lines to format the final product. How would you suggest going about this?
Example:
Raw- This is an example.
Stripped- This is an example.
Formatted- This is an example.
I just noticed that if I mark rich text on the UI text element, unity automatically bolds the text because it uses the tag. Goodbye an hour of wasted work.
If your gameâs simple, you could just use the Hierarchy and GameObject nesting to build your dialogue trees visually. Each line of dialogue would be a GameObject with a script on it containing the avatar/emotion/audio variables. They could be nested under âTopicâ GameObjects.
The major downside is that the âdataâ is contained in your scene (unless you reference txt/xml files), so if you changed a class in a major way (changed the name of a variable), the data will get wiped.
Sounds/emotions would just be variables on a MonoBehaviour.
For sounds, I have a sound take [sound=âresources pathâ] that gets triggered instead. So I donât need to mess with game objects. Just another thought.
I set up a scriptable object for each of my characters that has an array of Facial expression textures and an array of reaction voices. I then set up my Dialogue reader to check for a tag with the characters ID (EX: PC001) and then check my resources folder for a scriptable object that has the same ID and load it. After that its as simple as using more tags to indicate what expression and reaction voice to use.
A dialogue at itâs core is a Tree data structure of text, with additional formatting and events that can be triggered. So following the above I feel itâs pretty simple to write enough nodes to handle Dialogue:
I.e I have the following nodes (Which are ScriptableObjects):
Text Node - This is just text. It can read in ârich textâ and have options in [ ] to link to items\abilities\information in other parts of the game. This is handled by the DialogueReader.
Action Node - This will send an event from the DialogueReader with some information on what the action is (I.e Exit Conversation, Change Mood(Player says something the character hates, this will change their face), Start Event and Set Variable. My dialogue has a globally accessible variable storage to handle story elements changing dialogue with simple logic to handle it within the dialogue tree.
Branch Node - This will branch based on a variable equaling one or many things.
My API for the reader looks something like this:
someDialogue.OnAction += (action) {
// Do thing based on action. Open shop.
}
Dialogue dialogue= someDialogue.GetNextText(); // Will branch and call any events if needed and change\add variables.
// Dialogue has the characters text and the players responses.
dialogueView.SetText(dialogue.characterText);
dialogueView.SetReponses(dialogue.playerResponses);
On top of this I have the ability to load the dialogue from a database or JSON file which is easy once the structure is setup.
Hereâs a video walkthrough of a partial solution. This shows how to write dialogue in an easy to write JSON format, read it, and display it with a bit of polish.
Here are a couple more videos that set up a dialogue system similar to the Fire Emblem style listed above. These emphasize making it easy to build dialogue within Unity in the inspector
Canât believe no oneâs posted up Brackeyâs tutorial yet, he also shows you how to do incrementing text.
What I would do is just follow this tutorial and then I would activate my dialogue options based on what buttons were pressed, no need for anything ridiculously complicated.