Hi there guys, just posting here to share a dialogue script I’ve been working on. It’s fairly simple and uses just this one script and an additional serialized class in an array to prove the data for each line of dialogue.
I was wondering if anybody would be willing to offer any feedback on the code, ways to improve or possibly implement a multiple-choice answer in there.
My initial thoughts were to add a boolean to the dialogueNode script that dictates if that line of dialogue has a multiple choice. As it cycles through the dialogue nodes, if a node has a question then to set a specific number in the array as the following text box.
Current features: Change colour, Sprite, SFX, Typewriter effect for each line of text.
Desired features: Branching dialogue, Rewards
Not sure if anybody is able to offer advice on this? Feel free to use the code or to rip it to shreds, whatever you fancy
My current thoughts are:
- Create an Array of Dialogue Arrays?
- When you reach a dialogue branch, based on your response, the dialogue box can continue down one of two specified separate arrays of dialogue nodes.
- Adding a reward won’t be too hard, I can just add an Item to the dialogue node script.
If it isn’t null then I can set the sprite to the item sprite and use some generic text for receiving the item. From there I could just use LastLine and end the dialogue or continue with subsequent dialogue nodes.
Thanks for the feedback and advice.
This is how it turned out looking in the inspector.
Any advice on the dialogue choice part would be great. Thanks
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Collections;
// My own dialogue system.
//
// Features to Add:
//
// Quest Giving / Rewards ( Need to be attached to the player inventory and Stats scriptables)
// Audio clip and animated pointer to represent moving to the next page of the dialogue.
public class DialogueSystem : Interactable
{
[Header("Dialogue UI Elements")]
[Tooltip("Dialogue Box Game object within the UI canvus. This is the parent to the TMPro text box and contains the BG image")]
public GameObject dialogueBox;
[Tooltip("TMPro text box")]
public TextMeshProUGUI dialogueText;
[Tooltip("Image for the character portrait sprite")]
public Image dialoguePortrait;
private int currentLine; // Current line progresses the script through the array.
private int totalLines; //Total lines in determined by the dialogue lines Array.
private bool lineComplete; // Bool to determine wether the text has finished displaying and the player can continue.
private bool lastLine = false; //If last line is true, next click will end the dialogue and reset it.
private string currentText = ""; //Current text is used within the coroutine for loop to create the type writer effect.
public float delay = 0.05f; //This should be repalced with a FloatValue which change be changed to adjust in game text speed.
[Header("Dialogue Details")]
public List<DialogueNode> dialogueNode = new List<DialogueNode>();
//-----------------------------------Start is called once upon creation-------------------------
public void Start()
{
lineComplete = false;
totalLines = dialogueNode.Count;
}
//-----------------------------------Update is called once per frame----------------------------
void Update()
{
// Checks that the last line of dialogue has been reached.
if (currentLine == totalLines - 1)
{
lastLine = true;
}
// Update function on the signpost / character / npc to check that you are in range, and the various conditions.
// If the player goes out of range the dialogue is quit and the place in the dialogue is reset.
if (Input.GetButtonDown("Fire1") && playerInRange)
{
CheckDialoguePosition();
}
}
//-----------------------------------Check the position in the Dialogue--------------------------
public void CheckDialoguePosition()
{
if (dialogueBox.activeInHierarchy == false && playerInRange)
{
dialogueBox.SetActive(true);
ResetDialogue();
DialogueNode thisNode = dialogueNode[currentLine];
StartCoroutine(DisplayNextSentence(thisNode.lineOfDialogue, thisNode.dialogueSprite, thisNode.textColor, thisNode.speakerFont, delay, thisNode.speechClip));
}
if (lastLine == false && dialogueBox.activeInHierarchy == true && playerInRange && lineComplete)
{
currentLine += 1;
DialogueNode thisNode = dialogueNode[currentLine];
StartCoroutine(DisplayNextSentence(thisNode.lineOfDialogue, thisNode.dialogueSprite, thisNode.textColor, thisNode.speakerFont, delay, thisNode.speechClip));
}
if (lastLine == true && lineComplete == true && playerInRange)
{
EndDialogue();
}
}
//-----------------------------------Change the Text and Sprite-------------------------------
protected IEnumerator DisplayNextSentence(string _LineOfText, Sprite _Sprite, Color _textColor, TMP_FontAsset _textFont, float _delay, AudioClip _sound)
{
dialoguePortrait.sprite = _Sprite;
dialogueText.font = _textFont;
dialogueText.color = _textColor;
dialoguePortrait.preserveAspect = true;
lineComplete = false;
for (int i = 0; i < _LineOfText.Length + 1; i++)
{
currentText = _LineOfText.Substring(0, i);
dialogueText.GetComponent<TextMeshProUGUI>().text = currentText;
SoundManager.instance.PlaySound(_sound);
yield return new WaitForSeconds(_delay);
if (i == _LineOfText.Length - 1)// Allows the player to click once the dialogue has been completed
{
lineComplete = true;
SoundManager.instance.StopSound();
yield return new WaitUntil(() => Input.GetMouseButton(0));
}
}
}
//Closes the dialogue, resets the dialogue
//-----------------------------------End the Dialogue-----------------------------------------
public void EndDialogue()
{
ResetDialogue();
SoundManager.instance.StopSound();
dialogueBox.SetActive(false);
}
//This is used to reset the dialogue when cycling through for a second or third time.
//-----------------------------------Reset the Dialogue---------------------------------------
public void ResetDialogue()
{
currentLine = 0;
lastLine = false;
}
//Context.Raise doesn't really relate to this script.
//-----------------------------------Context Clue---------------------------------------------
public void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player") && !other.isTrigger)
{
context.Raise();
playerInRange = true;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Player") && !other.isTrigger)
{
context.Raise();
playerInRange = false;
SoundManager.instance.StopSound();
dialogueBox.SetActive(false);
}
}
}
using TMPro;
using UnityEngine;
[System.Serializable]
public class DialogueNode {
[Header("Line of Dialogue")]
public string lineOfDialogue;
public Sprite dialogueSprite;
public TMP_FontAsset speakerFont;
public Color textColor; //Set colour of each line of dialogue text. Could be used to highlight key information or add emphasis.
public AudioClip speechClip; //Add undertale style very short clips to be repeated for old school dialogue effect
public bool dialogueChoice;
}