Как я могу удалить текущий элемент игрового индекса из списка, но переменная 'i' теперь равна 1, а не 0? - PullRequest
1 голос
/ 13 мая 2019

В скрипте:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class NaviDialogue : MonoBehaviour
{
    public ObjectsManipulation op;
    public bool scaling = true;
    public Scaling scale;
    public ConversationTrigger conversationTrigger;

    private bool ended = false;
    private bool startConversation = false;

    private void Update()
    {
        if (scaling == true && DOFControl.hasFinished == true)
        {
            DOFControl.hasFinished = false;
            scaling = false;
            op.Scaling();
            PlayerController.disablePlayerController = true;
            ConversationTrigger.conversationsToPlay.Add(0);
            ConversationTrigger.conversationsToPlay.Add(1);
            ConversationTrigger.conversationsToPlay.Add(2);
            StartCoroutine(conversationTrigger.PlayConversations());
        }
}

И в верхней части ConversationTrigger:

public static List<int> conversationsToPlay = new List<int>();

В методе PlayConversations:

public IEnumerator PlayConversations()
    {
        for (int i = 0; i < conversationsToPlay.Count; i++)
        {
            yield return StartCoroutine(PlayConversation(conversationsToPlay[i]));
        }
    }

И метод воспроизведения разговора:

public IEnumerator PlayConversation(int index)
    {
        isRunning = true;

        if (conversations.Count > 0 &&
            conversations[index].Dialogues.Count > 0)
        {
            for (int i = 0; i < conversations[index].Dialogues.Count; i++)
            {
                if (dialoguemanager != null)
                {
                    dialoguemanager.StartDialogue(conversations[index].Dialogues[i]);
                }

                while (DialogueManager.dialogueEnded == false)
                {
                    yield return null;
                }
            }

            conversationIndex = index;
            conversationEnd = true;
            canvas.SetActive(false);
            Debug.Log("Conversation Ended");
            conversationsToPlay.Remove(index);
        }
    }

В последнем методе Play Conversation я удаляю текущий воспроизводимый элемент:

conversationsToPlay.Remove(index);

Проблема состоит в том, что в методе PlayConversations теперь значение I равно 1, поэтому он будет воспроизводить следующий последний элемент. Поэтому, если есть 3 предмета, он будет играть первым и последним, но средний не будет воспроизведен.

Ответы [ 2 ]

3 голосов
/ 13 мая 2019

Вы никогда не должны изменять коллекцию, по которой вы сейчас выполняете итерацию (проблема, с которой вы столкнулись, является одной из причин этого).В вашем случае есть несколько вариантов, простое решение может быть скопировать список разговоров и в то же время очистить исходный список:

public IEnumerator PlayConversations()
{
    var conversations = conversationsToPlay.ToArray(); // Copy the list
    conversationsToPlay.Clear(); // Immediately clear the original list

    for (int i = 0; i < conversations.Length; i++) // iterate over the array
    {
        // Now you also don't need to remove items anymore, 
        // since you already cleared the list
        yield return StartCoroutine(PlayConversation(conversations[i]));
    }
}

Созданный вами массив остается локальным для сопрограммы,так что вы можете очистить оригинальный список и работать с копией.

В качестве альтернативы, вы можете просто изменить цикл на цикл while и обрабатывать список с самого начала, пока он не будет пустым:

public IEnumerator PlayConversations()
{
    while (conversationsToPlay.Count > 0)
    {
        // Better remove the item right here, close to the loop condition. 
        // Makes things easier to understand.
        var conversationIndex = conversationsToPlay[0];
        conversationsToPlay.RemoveAt(0);
        yield return StartCoroutine(PlayConversation(conversationIndex));

    }
}

При переходе ко второму примеру вы можете простодля разговоров лучше использовать Queue<T> вместо List<T>, поскольку очередь разработана специально с учетом первоочередного, первоочередного доступа.

2 голосов
/ 13 мая 2019

Если у вас нет бизнес-требования для поддержания порядка, всегда повторяйте коллекцию в обратном порядке, когда вы планируете удалять элементы. Это вы можете удалить элементы, не нарушая последовательность массива. Так вот

public IEnumerator PlayConversations()
{
    for (int i = conversationsToPlay.Count-1; i >=0;  i++)
    {
        yield return StartCoroutine(PlayConversation(conversationsToPlay[i]));
    }
}

Этот метод в целом работает для всех ситуаций, когда мы удаляем что-то из коллекции. Однако отметим, что удаление разговора в методе Playconversation - просто плохая практика. в конечном итоге вам будет сложно поддерживать код. Удалите его каким-нибудь способом, который специально для этой цели. в противном случае вы нарушаете SRP

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...