So this is my issue, I'm trying to make a simple game on Unity with a dialogue box component. On trigger the dialogue box pop up and a text shows up when the next button is clicked the displayNext() function is called and it displays the next part of the dialogue. I'm trying to to add a back button to go back to the previous part of the dialogue but I'm not sure how to do that using Queues. I'd like to avoid changing my data structures since the rest of my code uses queues. Would love to hear you feed back.
public class DialogueManager : MonoBehaviour
{
private Queue<string> informations;
public Text buildingNameText;
public Text informationText;
public Animator animator;
public UnityEvent dialogueFinished;
// Start is called before the first frame update
void Start()
{
informations = new Queue<string>();
}
public void StartDialogue (Dialogue dialogue) {
Debug.Log("Display information about " dialogue.buildingName);
animator.SetBool("IsOpen",true);
buildingNameText.text = dialogue.buildingName;
informations.Clear();
foreach (string information in dialogue.informations)
{
informations.Enqueue(information);
}
DisplayNext();
}
public void DisplayNext(){
Debug.Log("Display next1");
if (informations.Count==0){
EndDialogue();
return;
}
Debug.Log("Display next2");
string information = informations.Dequeue();
StopAllCoroutines();
Debug.Log(information);
StartCoroutine(TypeSentence(information));
}
public void DisplayBack(){
Debug.Log("Display back");
if (informations.Count==0){
EndDialogue();
return;
}
Debug.Log("Display back1");
// No idea what to put here
StopAllCoroutines();
StartCoroutine(TypeSentence(removed));
}
IEnumerator TypeSentence (string information)
{
informationText.text ="";
foreach(char letter in information.ToCharArray()){
informationText.text = letter;
yield return null;
}
}
public void EndDialogue(){
Debug.Log("end");
animator.SetBool("IsOpen",false);
dialogueFinished.Invoke();
}
}
CodePudding user response:
One of your stipulations was that you wanted to work with the Queues, because they are prominent in your code. I would like to point out that for what I understand of the situation though, they very much seem like the wrong collection for the job.
That being said, you can make a simple temporary list of string that represent the queue data, and then move back and forward through the list instead of a queue. Like so:
public class DialogueManager : MonoBehaviour
{
public Text buildingNameText;
public Text informationText;
public Animator animator;
public UnityEvent dialogueFinished;
private List<string> dialogueStrings = new();
public int currentIndex { get; private set; }
public void StartDialogue ( Dialogue dialogue )
{
Debug.Log ( $"Display information about {dialogue.buildingName}. {dialogue.informations.Count} dialogue items." );
animator.SetBool ( "IsOpen", true );
buildingNameText.text = dialogue.buildingName;
dialogueStrings.Clear ( );
currentIndex = 0;
foreach ( var s in dialogue.informations )
dialogueStrings.Add ( s );
DisplayNext ( );
}
public void DisplayNext ( )
{
Debug.Log ( $"DisplayNext: currentIndex = {currentIndex}. count = {dialogueStrings.Count}" );
if ( dialogueStrings.Count == 0 || currentIndex >= dialogueStrings.Count )
{
EndDialogue ( );
return;
}
StopAllCoroutines ( );
Debug.Log ( dialogueStrings[ currentIndex ] );
StartCoroutine ( TypeSentence ( dialogueStrings [ currentIndex ] ) );
}
public void DisplayBack ( )
{
Debug.Log ( $"DisplayBack: currentIndex = {currentIndex}" );
if ( currentIndex <= 0 )
return;
--currentIndex;
StopAllCoroutines ( );
StartCoroutine ( TypeSentence ( dialogueStrings [ currentIndex ] ) );
}
IEnumerator TypeSentence ( string information )
{
informationText.text = "";
foreach ( char letter in information.ToCharArray ( ) )
{
informationText.text = letter;
yield return null;
}
}
public void EndDialogue ( )
{
Debug.Log ( "end" );
animator.SetBool ( "IsOpen", false );
dialogueFinished.Invoke ( );
}
}
CodePudding user response:
You would need to replace your Queue
with a List
, because that will enable you to add items back that you have already removed. As you remove an item, push it onto a Stack
. To go back, pop the last item from the Stack
and you can then re-add it to the original List
. You might want to create your own custom class, inheriting List<T>
or Collection<T>
and add Enqueue
, Dequeue
and Requeue
methods. E.g.
public class QueueList<T> : List<T>
{
public void Enqueue(T item)
{
Add(item);
}
public void Requeue(T item)
{
Insert(0, item);
}
public T Dequeue()
{
var item = this[0];
RemoveAt(0);
return item;
}
}
private QueueList<string> items = new QueueList<string>();
private string currentItem;
private Stack<string> history = new Stack<string>();
private bool Next()
{
if (!items.Any())
{
return false;
}
if (currentItem != null)
{
history.Push(currentItem);
}
currentItem = items.Dequeue();
return true;
}
private bool Previous()
{
if (history.Count == 0)
{
return false;
}
items.Requeue(currentItem);
currentItem = history.Pop();
return true;
}
If you don't mind adding your initial list of items in reverse order then you could do away with the QueueList
and just use a second Stack
.