DataStructures: List, Queue - For ConversationEntries
Now, we just have to figure out how to write the code logic. We need a List of ConversationEntry items, then we need to display them sequentially when the next button has been clicked.
Unity can display for editing, both List< string >, or array: string[] in the inspector below.
List< T > is part of the System.Collections.Generic Namespace in C#. MSDN Reference
Queue< T > is a data structure that operates like a queue / waiting line. It will make it easy to remove each sequential dialog item from the collection so it can be displayed in sequence.MSDN Reference
SimpleDialog.cs
(See complete code at bottom of page)
We will have several different versions of classes that can be used for creating and managing conversations. Subsequent versions will have slightly more complex code, but they will be easier to use in Unity.
In the code below we specify that the List< T > and Queue< T > will both be collections of ConversationEntry objects.
privateQueue<ConversationEntry> conversationsQueue =newQueue<ConversationEntry>();publicList<ConversationEntry> conversations; //initialized by Unity in Inspector
Declare object reference variables for the components we'll interact with.
publicButton openButton;publicCanvasGroup nextPanelToOpen;public bool showOnStart =false;//find in childrenprivateButton nextButton; //only 1 child button private Text dialogText; //find as a child - Hierarchy order mattersprivate CanvasGroup dialogCG; //Canvas Group on top level - script attached to this Panel
privateText speakerText; //find as a child - Hierarchy order mattersprivateCanvasGroup dialogCG; //top level panel
Start: Initialize Object Reference Variables
The following logic would be located in the Unity Start( ) event function for this script that's attached to the panel gameObject:
// Use this for initializationvoidStart() { dialogCG =GetComponent<CanvasGroup>();//Find all children Text elements of current Panel GameObjectText[] textChildren =GetComponentsInChildren<Text>(); dialogText = textChildren[0]; //first child Text speakerText = textChildren[2]; //3rd child TextInitializeDialog(); //populate Queue, set initial conversation values nextButton =GetComponentInChildren<Button>();nextButton.onClick.AddListener(GetNextDialog);if (!showOnStart) //Should this be hidden at Start { //is there a button to display panelif (openButton !=null) {openButton.onClick.AddListener(ShowDialogPanel); }Utility.HideCG(dialogCG); //hide initially }else//show on start {Utility.ShowCG(dialogCG); } }//end start
GetComponentsInChildren< Text >()See section below for details
Populate the queue data structure
Initialize DialogQueue
In the code below we specify that the List< T > and Queue< T > will both be collections of ConversationEntry objects.
voidInitializeDialog() {foreach( ConversationEntry item in conversations) {conversationsQueue.Enqueue(item); //put each string -item in the queue }GetNextDialog(); //get first item }
GetNextDialog Method
The nextButton allows the user to move forward through the dialogue items. In the Start( ) method, we configured the nextButton's onClick method to execute the GetNextDialog method each time it is clicked. The code below shows that each time the GetNextDialog method is executed, it first checks to make sure there are items in the queue. Then, the dialogText is updated to display the first item in the queue. The Queue< T > Dequeue( ) method retrieves and removes the item at the front of the queue returns that value so it can be used to set the text value for the dialogText. If there are no more items in the queue, then the panel is hidden, using the Utility class static method: HideCG.
voidGetNextDialog() {if (conversationsQueue.Count>0) {ConversationEntry item =conversationsQueue.Dequeue();dialogText.text=item.dialogTxt;speakerText.text=item.speakerName; }else { //no more dialogif ( nextPanelToOpen !=null) {Utility.ShowCG(nextPanelToOpen); }Utility.HideCG(dialogCG); //hide the dialog } }//Helper Method, allows Button-click To Execute Utility.ShowCG( )publicvoidShowDialogPanel() {Utility.ShowCG(dialogCG); }//end function
Unity: GetComponentsInChildren< T >()
The Unity method: GetComponentsInChildren, provides a convenient way to initialize an object reference variable based on the Hierarchy panel's parent-child relationships between gameObjects.
In the code above, we've specified that we want to initialize the Text component reference variable: dialogText, speakerText. Since the current script is on the DialogPanel in our custom prefab, and since there is a UI-Text gameObject that is a child of the DialogPanel, we can access the components on that child object using this method.
Important: Note that this method will find all < T > components while traversing the Parent-child relationships of the gameObject that this script is attached to. So, make sure to order your gameObjects in the hierarchy correctly if you plan to use this method.
Unity also has a similar method: GetComponentsInChildren< T >(), which returns an array of all matching object in children that are ordered according to parent-to children ordering in the hierarchy.Unity Manual
SimpleDialog.cs Complete Code
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;publicclassSimpleDialog : MonoBehaviour{publicButton openButton;publicCanvasGroup nextPanelToOpen;public bool showOnStart =false;//find in childrenprivateButton nextButton; //only 1 child button private Text dialogText; //find as a child - Hierarchy order mattersprivate CanvasGroup dialogCG; //Canvas Group on top level - script attached to this Panel
privateText speakerText; //find as a child - Hierarchy order mattersprivateCanvasGroup dialogCG; //top level panelprivateQueue<ConversationEntry> conversationsQueue =newQueue<ConversationEntry>();publicList<ConversationEntry> conversations;// Use this for initializationvoidStart() { dialogCG =GetComponent<CanvasGroup>();Text[] textChildren =GetComponentsInChildren<Text>(); dialogText = textChildren[0]; speakerText = textChildren[2];InitializeDialog(); nextButton =GetComponentInChildren<Button>();nextButton.onClick.AddListener(GetNextDialog);if (!showOnStart) { //click button to display panelif (openButton !=null) {openButton.onClick.AddListener(ShowDialogPanel); }Utility.HideCG(dialogCG); //hide initially }else//show on start {Utility.ShowCG(dialogCG); } }//end startvoidInitializeDialog() {foreach (ConversationEntry item in conversations) {conversationsQueue.Enqueue(item); //put each string -item in the queue }GetNextDialog(); //get first item }voidGetNextDialog() {if (conversationsQueue.Count>0) {ConversationEntry item =conversationsQueue.Dequeue();dialogText.text=item.dialogTxt;speakerText.text=item.speakerName; }else { //no more dialogif (nextPanelToOpen !=null) {//Before displaying nextPanelToOpen, if it's OptionPanel, get the buttons setUtility.ShowCG(nextPanelToOpen); }Utility.HideCG(dialogCG); //hide the dialog } }publicvoidStartInitialDialog() {Utility.ShowCG(dialogCG);Debug.Log("Show and Starting Dialog"); }publicvoidShowDialogPanel() {Utility.ShowCG(dialogCG); }//end function} //end class