Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Question How to start dialog on differently and continue as long as player presses "E" key?

Discussion in 'UGUI & TextMesh Pro' started by IgorArnaut, Aug 27, 2022.

  1. IgorArnaut

    IgorArnaut

    Joined:
    Nov 15, 2021
    Posts:
    39
    Hello. I have made a universal Dialog Manager that has DialogManager script. In one scene I have Terminal GameObject that starts dialog when the player is in range and presses "E" and in the Battle scene dialog starts automatically when the player wins or loses a battle (condition in BattleManager script).

    Terminal.cs:
    Code (CSharp):
    1. public class Terminal : MonoBehaviour
    2. {
    3.      private Animator anim;
    4.  
    5.      private GameObject clue;
    6.  
    7.      [SerializeField]
    8.      private DialogManager manager;
    9.  
    10.      [SerializeField]
    11.      private string[] lines;
    12.  
    13.      private bool inRange;
    14.  
    15.      // Use this for initialization
    16.      void Start()
    17.      {
    18.          anim = GetComponent<Animator>();
    19.          clue = GameObject.FindGameObjectWithTag("Player").transform.GetChild(0).gameObject;
    20.      }
    21.  
    22.      // Update is called once per frame
    23.      void Update()
    24.      {
    25.          if (inRange && Input.GetKeyDown(KeyCode.E))
    26.              manager.Write(lines);
    27.      }
    28.  
    29.      private void OnTriggerEnter2D(Collider2D collision)
    30.      {
    31.          if (collision.gameObject.CompareTag("Player"))
    32.          {
    33.              inRange = true;
    34.              anim.SetBool("inRange", true);
    35.              clue.SetActive(true);
    36.              clue.GetComponent<Animator>().SetInteger("clue", 1);
    37.          }
    38.      }
    39.  
    40.      private void OnTriggerExit2D(Collider2D collision)
    41.      {
    42.          if (collision.gameObject.CompareTag("Player"))
    43.          {
    44.              inRange = false;
    45.              anim.SetBool("inRange", false);
    46.              clue.SetActive(false);
    47.              clue.GetComponent<Animator>().SetInteger("clue", 0);
    48.              manager.textBox.SetActive(false);
    49.          }
    50.      }
    51. }
    52.  
    BattleManager.cs:
    Code (CSharp):
    1. public class BattleManager : MonoBehaviour
    2. {
    3.      private string[] defeat = { "You are defeated!" };
    4.      private string[] victory = { "Enemy has been defeated!", "You are victorius!" };
    5.  
    6.      private GameObject player;
    7.      private GameObject enemy;
    8.  
    9.      [SerializeField]
    10.      private DialogManager dManager;
    11.      [SerializeField]
    12.      private SceneManager2 sManager;
    13.  
    14.      void Start()
    15.      {
    16.          player = GameObject.FindGameObjectWithTag("Player");
    17.          enemy = GameObject.FindGameObjectWithTag("Enemy");
    18.      }
    19.  
    20.      void Update()
    21.      {
    22.          if (player == null) {
    23.              Debug.Log("You have lost!");
    24.              dManager.Write(defeat);
    25.          }
    26.  
    27.          if (enemy == null) {
    28.              Debug.Log("You have won!");
    29.              dManager.Write(victory);
    30.          }
    31.      }
    32. }
    33.  
    Here is my attempt, but I get index out of bounds for some reason.

    DialogManager.cs:
    Code (CSharp):
    1. public class DialogManager : MonoBehaviour
    2. {
    3.      public GameObject textBox;
    4.      private TMP_Text dialogText;
    5.  
    6.      private bool running;
    7.      [SerializeField]
    8.      private int index = -1;
    9.  
    10.      void Start()
    11.      {
    12.          textBox = transform.GetChild(0).gameObject;
    13.          dialogText = textBox.GetComponentInChildren<TextMeshProUGUI>();
    14.      }
    15.  
    16.      public void Write(string[] lines)
    17.      {
    18.          textBox.SetActive(true);
    19.          index++;
    20.          StartCoroutine(Write(lines[++index]));
    21.  
    22.          if (Input.GetKeyDown(KeyCode.E) && !running)
    23.          {
    24.              if (textBox.activeInHierarchy && index > lines.Length - 1)
    25.              {
    26.                  textBox.SetActive(false);
    27.                  index = -1;
    28.              }
    29.              else
    30.              {
    31.                  if (index < lines.Length) {
    32.                      index++;
    33.                      StartCoroutine(Write(lines[index]));
    34.                  }
    35.              }
    36.          }
    37.      }
    38.  
    39.      private IEnumerator Write(string line)
    40.      {
    41.          running = true;
    42.          dialogText.text = "";
    43.  
    44.          foreach (char c in line)
    45.          {
    46.              dialogText.text += c;
    47.              yield return new WaitForSeconds(0.01f);
    48.          }
    49.  
    50.          running = false;
    51.      }
    52. }
    53.  
     
    Last edited: Aug 27, 2022
  2. IgorArnaut

    IgorArnaut

    Joined:
    Nov 15, 2021
    Posts:
    39
    I want it to be like this:
    (Press E or other condition) -> first line
    Press E -> second line
    Press E -> third line
    Press E -> END.
     
  3. IgorArnaut

    IgorArnaut

    Joined:
    Nov 15, 2021
    Posts:
    39
    I tried to fix this by using queues, but I now I have different problems. Anyone help me, please.

    BattleManager.cs skips writing part and immediately changes scene:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using TMPro;
    5.  
    6. public class BattleManager : MonoBehaviour
    7. {
    8.     [SerializeField]
    9.     private List<string> defeat;
    10.     [SerializeField]
    11.     private List<string> victory;
    12.  
    13.     private GameObject player;
    14.     private GameObject enemy;
    15.  
    16.     [SerializeField]
    17.     private SceneManager2 sManager;
    18.  
    19.     public GameObject textBox;
    20.     private TMP_Text dialogText;
    21.  
    22.     private bool running;
    23.  
    24.     void Start()
    25.     {
    26.         player = GameObject.FindGameObjectWithTag("Player");
    27.         enemy = GameObject.FindGameObjectWithTag("Enemy");
    28.  
    29.         textBox = transform.GetChild(0).gameObject;
    30.         dialogText = textBox.GetComponentInChildren<TextMeshProUGUI>();
    31.     }
    32.  
    33.     void Update()
    34.     {
    35.         if (player == null) {
    36.             Write(new Queue<string>(defeat));
    37.             sManager.Transition("GameOver");
    38.         }
    39.  
    40.         if (enemy == null) {
    41.             Write(new Queue<string>(victory));
    42.             sManager.Transition("Dungeon");
    43.         }
    44.     }
    45.  
    46.     public void Write(Queue<string> lines)
    47.     {
    48.         textBox.SetActive(true);
    49.         StartCoroutine(Write(lines.Dequeue()));
    50.  
    51.         if (Input.GetKeyDown(KeyCode.E) && !running)
    52.         {
    53.             if (lines.Count == 0)
    54.             {
    55.                 textBox.SetActive(false);
    56.                 return;
    57.             }
    58.          
    59.             StartCoroutine(Write(lines.Dequeue()));
    60.         }
    61.     }
    62.  
    63.     private IEnumerator Write(string line)
    64.     {
    65.         running = true;
    66.         dialogText.text = "";
    67.  
    68.         foreach (char c in line)
    69.         {
    70.             dialogText.text += c;
    71.             yield return new WaitForSeconds(0.01f);
    72.         }
    73.  
    74.         running = false;
    75.     }
    76. }
    77.  
    DialogManager.cs repeats the first line:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using TMPro;
    5.  
    6. public class DialogManager : MonoBehaviour
    7. {
    8.     public GameObject textBox;
    9.     private TMP_Text dialogText;
    10.  
    11.     private bool running;
    12.  
    13.     void Start()
    14.     {
    15.         textBox = transform.GetChild(0).gameObject;
    16.         dialogText = textBox.GetComponentInChildren<TextMeshProUGUI>();
    17.     }
    18.  
    19.     public void Write(Queue<string> lines)
    20.     {
    21.         textBox.SetActive(true);
    22.  
    23.         if (Input.GetKeyDown(KeyCode.E) && !running)
    24.         {
    25.             if (lines.Count == 0)
    26.             {
    27.                 textBox.SetActive(false);
    28.                 return;
    29.             }
    30.          
    31.             StartCoroutine(Write(lines.Dequeue()));
    32.         }
    33.     }
    34.  
    35.     private IEnumerator Write(string line)
    36.     {
    37.         running = true;
    38.         dialogText.text = "";
    39.  
    40.         foreach (char c in line)
    41.         {
    42.             dialogText.text += c;
    43.             yield return new WaitForSeconds(0.01f);
    44.         }
    45.  
    46.         running = false;
    47.     }
    48. }
    49.  
    Terminal.cs:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class Terminal : MonoBehaviour
    5. {
    6.     private Animator anim;
    7.  
    8.     private GameObject clue;
    9.  
    10.     [SerializeField]
    11.     private DialogManager manager;
    12.     [SerializeField]
    13.     private List<string> lines;
    14.     private bool inRange;
    15.  
    16.     // Use this for initialization
    17.     void Start()
    18.     {
    19.         anim = GetComponent<Animator>();
    20.  
    21.         clue = GameObject.FindGameObjectWithTag("Player").transform.GetChild(0).gameObject;
    22.     }
    23.  
    24.     // Update is called once per frame
    25.     void Update()
    26.     {
    27.         if (inRange && Input.GetKeyDown(KeyCode.E))
    28.             manager.Write(new Queue<string>(lines));
    29.     }
    30.  
    31.     private void OnTriggerEnter2D(Collider2D collision)
    32.     {
    33.         if (collision.gameObject.CompareTag("Player"))
    34.         {
    35.             inRange = true;
    36.  
    37.             anim.SetBool("inRange", true);
    38.             clue.SetActive(true);
    39.             clue.GetComponent<Animator>().SetInteger("clue", 1);
    40.         }
    41.     }
    42.  
    43.     private void OnTriggerExit2D(Collider2D collision)
    44.     {
    45.         if (collision.gameObject.CompareTag("Player"))
    46.         {
    47.             inRange = false;
    48.  
    49.             anim.SetBool("inRange", false);
    50.             clue.SetActive(false);
    51.             clue.GetComponent<Animator>().SetInteger("clue", 0);
    52.             manager.textBox.SetActive(false);
    53.         }
    54.     }
    55. }
    56.  
     
  4. IgorArnaut

    IgorArnaut

    Joined:
    Nov 15, 2021
    Posts:
    39
    Anyone???
     
  5. DrJkJones

    DrJkJones

    Joined:
    Jan 9, 2022
    Posts:
    21
    I'm not entirely sure what you want to do, but likely you would need to use get key up and down rather than just down. You'd use up to detect when to allow the next E press, sorry if this doesn't help, at least it'll bump the post :)