Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Queue not running through all items?

Discussion in 'Scripting' started by dannyryba, Jul 9, 2020.

  1. dannyryba

    dannyryba

    Joined:
    Jun 22, 2020
    Posts:
    45
    Hi everyone!

    I am working on creating a simple dialogue system for a game, using some tutorials as guidance. I currently have a Queue system built for showing text, but for some reason all the sentences don't get run through, just the first one. I'm not sure where the problem lies as I am not 100% well-versed in Queues (just started learning about them). If anyone can help that would be great!

    Here is the DialogManager,
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class DialogManager : MonoBehaviour
    7. {
    8.  
    9.     public Text nameText;
    10.     public Text dialogText;
    11.     //create a queue to load sentences in queue order (FIFO)
    12.     private Queue<string> sentences;
    13.    
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         sentences = new Queue<string>();
    18.     }
    19.  
    20.     public void StartDialog (Dialog dialog)
    21.     {
    22.         nameText.text = dialog.name;
    23.        
    24.         sentences.Clear(); //clear any sentences in the queue
    25.  
    26.         foreach (string sentence in dialog.sentences) //for each sentence, enqueue it
    27.         {
    28.             sentences.Enqueue(sentence);
    29.         }
    30.  
    31.         DisplayNextSentence(); //then run the display method
    32.  
    33.     }
    34.  
    35.     public void DisplayNextSentence ()
    36.     {
    37.         if(sentences.Count ==0) //if no more sentences
    38.         {
    39.             EndDialog(); //end the dialog
    40.             return;
    41.         }
    42.  
    43.         string sentence = sentences.Dequeue(); //otherwise, dequeue the sentences (FIFO order)
    44.         dialogText.text = sentence;
    45.     }
    46.  
    47.     void EndDialog()
    48.     {
    49.  
    50.     }
    51. }
    Here is the Dialog class:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class Dialog
    7. {
    8.     //this passes to DIalogManager whenever we start a new dialog
    9.     //has all info we need for a dialog
    10.  
    11.     public string name;
    12.    
    13.     [TextArea(1, 10)] //specifies minimum and maximum amount of lines the text uses
    14.     public string[] sentences;
    15.  
    16. }
    And here is the Trigger script. The eventual idea is to have a player enter a trigger collider, hit space, and see the text, though I haven't created the collider or anything yet and was simply testing just activating via spacebar when I discovered it not working correctly.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DialogTrigger : MonoBehaviour
    6. {
    7.     // Put this on an object that will trigger dialog (NPC, button, etc)
    8.     public Dialog dialog;
    9.     private bool canActivate = true;
    10.  
    11.  
    12.     private void Update()
    13.     {
    14.        if(canActivate && Input.GetKeyDown("space"))
    15.         {
    16.             TriggerDialog();
    17.         }
    18.  
    19.     }
    20.     public void TriggerDialog()
    21.     {
    22.         FindObjectOfType<DialogManager>().StartDialog(dialog);
    23.     }
    24. }
    Please let me know if I need to provide any more information!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,932
    I only see you calling
    DisplayNextSentence()
    once, in
    StartDialog()
    . Is there somewhere else you're calling it to try to go through all the sentences? Otherwise it seems like you're just calling
    StartDialog()
    every time you hit space, which will restart the dialog from the beginning each time.
     
    dannyryba likes this.
  3. dannyryba

    dannyryba

    Joined:
    Jun 22, 2020
    Posts:
    45
    No, it's not being called anywhere else.

    So if space is simply starting the dialog over each time, how can I get the script to run through each sentence in the dialog? For example, if I have three sentences that need to be run through before it ends?

    In the tutorial I followed for most of this from Brackeys (
    ), he creates a button that can progress the text. However, since I am coding a keycode, that is probably where I am not clear on how the interaction needs to be working.
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,932
    If you want to use the same button for starting the dialog as continuing the already started dialog dialog, you will need to add some logic when the user hits the space bar. Something like this:
    • If there is no dialog currently in progress, call StartDialog()
    • If there is a dialog currently in progress, call DisplayNextSentence()
     
    dannyryba likes this.
  5. dannyryba

    dannyryba

    Joined:
    Jun 22, 2020
    Posts:
    45
    Hm, okay that makes sense! Thank you for the insight. So I accomplished this by changing the DialogTrigger to the following code and it works!


    Code (CSharp):
    1. public class DialogTrigger : MonoBehaviour
    2. {
    3.     // Put this on an object that will trigger dialog (NPC, button, etc)
    4.     public Dialog dialog;
    5.     private bool canActivate = true;
    6.     private bool dialogStarted = false;
    7.  
    8.  
    9.     private void Update()
    10.     {
    11.        if(canActivate && Input.GetKeyDown("space"))
    12.             if(dialogStarted)
    13.             {
    14.                 ContinueDialog();
    15.             }
    16.             else
    17.             {
    18.                 BeginDialog();
    19.             }
    20.     }
    21.     public void BeginDialog()
    22.     {
    23.         dialogStarted = true;
    24.         FindObjectOfType<DialogManager>().StartDialog(dialog);
    25.     }
    26.  
    27.     public void ContinueDialog()
    28.     {
    29.        
    30.         FindObjectOfType<DialogManager>().DisplayNextSentence();
    31.     }
    32. }
    Does this seem like the best way to make this work or is there a more streamlined way I could use?
     
    PraetorBlue likes this.
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,932
    That seems pretty good but you should think about what happens when the dialog is over. Do you want the player to be able to run back through the dialog again? They won't be able to with the current code because dialogStarted, once set to true, will never be set back to false.
     
    dannyryba likes this.
  7. dannyryba

    dannyryba

    Joined:
    Jun 22, 2020
    Posts:
    45
    Ah of course, that makes total sense. So I created

    public DialogTrigger dialogTrigger;

    in the DialogManager and then dragged my gameobject to it. Then I added to the DisplayNextSentence so the text can begin again:
    Code (CSharp):
    1. public void DisplayNextSentence ()
    2.     {
    3.         if(sentences.Count ==0) //if no more sentences
    4.         {
    5.             dialogTrigger.dialogStarted = false;
    6.             EndDialog(); //end the dialog
    7.             return;
    8.         }
    9.  
    10.         string sentence = sentences.Dequeue(); //otherwise, dequeue the sentences (FIFO order)
    11.         dialogText.text = sentence;
    12.     }
    It seems to be working! Does this seem like the correct approach?
     
  8. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,932
    This will work but I'm not sure it's the best because now both objects need references to each other. What if you made DisplayNextSentence return a bool variable indicating if the dialog was finished or not? Then you could check that return value in DialogTrigger and set dialogStarted to false if the dialog was finished.
     
    dannyryba likes this.
  9. dannyryba

    dannyryba

    Joined:
    Jun 22, 2020
    Posts:
    45
    Hm, okay so I see what you are saying. That way, we only are referencing from one script to another instead of to each other. However, here is what the scripts look like now: (I have added animations since starting this thread, so ignore that unless its relevant)


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class DialogManager : MonoBehaviour
    7. {
    8.  
    9.     public bool dialogFinished;
    10.     public Text nameText;
    11.     public Text dialogText;
    12.  
    13.     public Animator animator;
    14.     //create a queue to load sentences in queue order (FIFO)
    15.     private Queue<string> sentences;
    16.    
    17.     // Start is called before the first frame update
    18.     void Start()
    19.     {
    20.         sentences = new Queue<string>();
    21.     }
    22.  
    23.     public void StartDialog (Dialog dialog)
    24.     {
    25.         animator.SetBool("isOpen", true);
    26.        
    27.         nameText.text = dialog.name;
    28.        
    29.         sentences.Clear(); //clear any sentences in the queue
    30.  
    31.         foreach (string sentence in dialog.sentences) //for each sentence, enqueue it
    32.         {
    33.             sentences.Enqueue(sentence);
    34.         }
    35.  
    36.         DisplayNextSentence(); //then run the display method
    37.  
    38.     }
    39.  
    40.     public void DisplayNextSentence ()
    41.     {
    42.         if(sentences.Count ==0) //if no more sentences
    43.         {
    44.             dialogFinished = true;
    45.             EndDialog(); //end the dialog
    46.             return;
    47.         }
    48.  
    49.         string sentence = sentences.Dequeue(); //otherwise, dequeue the sentences (FIFO order)
    50.         dialogText.text = sentence;
    51.     }
    52.  
    53.     void EndDialog()
    54.     {
    55.         animator.SetBool("isOpen", false);
    56.     }
    57. }
    and:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DialogTrigger : MonoBehaviour
    6. {
    7.     // Put this on an object that will trigger dialog (NPC, button, etc)
    8.     public DialogManager dialogManager;
    9.     public bool canActivate = true;
    10.     public bool dialogStarted = false;
    11.  
    12.  
    13.     private void Update()
    14.     {
    15.        if(canActivate && Input.GetKeyDown("space"))
    16.             if(!dialogManager.dialogFinished)
    17.             {
    18.                 ContinueDialog();
    19.             }
    20.             else
    21.             {
    22.                 BeginDialog();
    23.             }
    24.     }
    25.     public void BeginDialog()
    26.     {
    27.         dialogManager.dialogFinished = false;
    28.         FindObjectOfType<DialogManager>().StartDialog(dialog);
    29.     }
    30.  
    31.     public void ContinueDialog()
    32.     {
    33.        
    34.         FindObjectOfType<DialogManager>().DisplayNextSentence();
    35.     }
    36. }
    However, I now get the error: Assets\Scripts\DialogTrigger.cs(28,55): error CS0103: The name 'dialog' does not exist in the current context

    I'm not sure why this is happening, when it was fine before. Did I mess something up without realizing it?