I have a dialogue system in my game, and I recently found out how to add letters one by one for dialogues through the use of coroutine. I wanted to skip that adding letters animation when the screen is clicked and then make the dialogue complete instantly.
I have here a coroutine which loops through the letters of a sentence or a string and displaying it in my dialogue text object. I cannot find a specific keyword for finishing coroutines instantly. Is there a way to skip or finish the coroutine instantly so when the dialogue is clicked or the screen is clicked, the dialogue will instantly be complete?
The code for displaying the dialogue and the coroutine:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;
public class InformantDialogue : MonoBehaviour
{
// NPC DATA
private Informant informantJson;
[SerializeField] TextAsset characterData;
// DIALOG UI
[SerializeField] GameObject dialogBox, article;
[SerializeField] TextMeshProUGUI dialogue;
// DIALOG CYCLE VARIABLES
private bool clickEnable;
private int dialogId, multiDialogCycle;
public int progress;
string[] multiDialog;
private void OnEnable()
{
setJSON();
loadCharacterData();
}
void Start()
{
dialogId = 1;
}
void Update()
{
if (Input.GetMouseButtonDown(0) && clickEnable == true)
{
Debug.Log(dialogId);
if (multiDialog.Length > 1)
{
if (multiDialogCycle == multiDialog.Length - 1)
{
closeDialog();
progressDialog();
}
else
{
multiDialogCycle ;
loadCharacterData();
}
}
else
{
closeDialog();
progressDialog();
}
}
}
public void loadCharacterData()
{
// DIALOGUE
multiDialog = getIDialog(dialogId).dialog_message.Split('#');
if (multiDialogCycle == 4)
{
article.SetActive(true);
}
if (multiDialog.Length == 1)
{
//dialogue.text = getIDialog(dialogId).dialog_message;
StopAllCoroutines();
StartCoroutine(TypeSentence(getIDialog(dialogId).dialog_message));
}
else if (multiDialogCycle < multiDialog.Length)
{
//dialogue.text = multiDialog[multiDialogCycle];
StopAllCoroutines();
StartCoroutine(TypeSentence(multiDialog[multiDialogCycle]));
clickEnable = true;
}
}
// INFORMANT DIALOGUE GETTER
public InformantDialog getIDialog(int dialogId)
{
foreach (InformantDialog dialog in informantJson.informant_dialogs)
{
if (dialog.id == dialogId)
{
return dialog;
}
}
return informantJson.informant_dialogs[0];
}
IEnumerator TypeSentence(string sentence)
{
dialogue.text = "";
foreach(char letter in sentence.ToCharArray())
{
dialogue.text = letter;
//yield return null;
yield return new WaitForSeconds(0.01f);
}
}
private void showDialogue()
{
dialogBox.SetActive(true);
}
private void closeDialog()
{
dialogBox.SetActive(false);
clickEnable = false;
multiDialogCycle = 0;
}
private void setJSON()
{
if (progress == 0)
{
characterData = Resources.Load<TextAsset>("JSON/Informant");
}else if (progress == 1)
{
characterData = Resources.Load<TextAsset>("JSON/Informant1");
}
else if (progress == 2)
{
characterData = Resources.Load<TextAsset>("JSON/Informant2");
} else
{
clickEnable = false;
}
informantJson = JsonUtility.FromJson<Informant>(characterData.text);
}
private void progressDialog()
{
if (dialogId == informantJson.informant_dialogs.Length)
{
dialogId = 0;
progress ;
}
dialogId ;
}
}
CodePudding user response:
IEnumerator TypeSentence(string sentence)
{
boolThatStartFalseAndWillBeTrueWhenPlayerClickOnScreen = false;
dialogue.text = "";
foreach(char letter in sentence.ToCharArray())
{
if (boolThatStartFalseAndWillBeTrueWhenPlayerClickOnScreen)
{
dialogue.text = sentence;
break;
}
dialogue.text = letter;
//yield return null;
yield return new WaitForSeconds(0.01f);
}
}
CodePudding user response:
I've added my approach to coroutines. I prefer to keep handle to a coroutine and null it at the end of coroutine. Thus you can restart just that coroutine. FinishTypingSentence()
stops it and sets whole text where it should be.
string typedSentence;
private IEnumerator _typeSentenceCoroutine;
//Caching this will save some memory allocation.
WaitForSeconds waitFor01Seconds = new WaitForSeconds(0.01f);
void StartTypingSentence()
{
if (_typeSentenceCoroutine != null) StopCoroutine(_typeSentenceCoroutine);
_typeSentenceCoroutine = TypeSentence();
StartCoroutine(_typeSentenceCoroutine);
}
public void FinishTypingSentence()
{
if (_typeSentenceCoroutine != null) StopCoroutine(_typeSentenceCoroutine);
_typeSentenceCoroutine = null;
dialogue.text = typedSentence;
}
IEnumerator TypeSentence()
{
dialogue.text = "";
foreach (char letter in typedSentence.ToCharArray())
{
dialogue.text = letter;
yield return waitFor01Seconds;
}
_typeSentenceCoroutine = null;
}