简体   繁体   English

如何从列表中删除当前播放索引项,但变量“ i”现在为1而不是0?

[英]How can I remove the current playing index item from the list but the variable 'i' is now 1 and not 0?

In a script : 在脚本中:

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());
        }
}

And in the top of ConversationTrigger : 在ConversationTrigger的顶部:

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

In the method PlayConversations : 在PlayConversations方法中:

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

And the Play Conversation method : 和Play对话方法:

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);
        }
    }

In the last method Play Conversation I'm removing the current played item : 在最后一种方法“播放对话”中,我要删除当前播放的项目:

conversationsToPlay.Remove(index);

The problem is that in the PlayConversations method now I value is 1 so it will play next the last item. 问题在于,现在在PlayConversations方法中,我的值为1,因此它将在最后一项播放。 So if there are 3 items it will play the first and the last but the middle one will not be played. 因此,如果有3个项目,它将播放第一个和最后一个项目,但不会播放中间的项目。

You should never modify a collection you are currently iterating over (the problem you encountered is one of the reasons for that). 您永远不要修改当前正在迭代的集合(遇到的问题是这样做的原因之一)。 In your case, there are a few options, a simple solution could be to copy the list of conversations and at the same time clear the original list: 在您的情况下,有几个选项,一个简单的解决方案是复制对话列表,同时清除原始列表:

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]));
    }
}

The array you create stays local to the coroutine, so you can clear the original list and work with the copy. 您创建的阵列在协程中保持局部状态,因此您可以清除原始列表并使用副本。

Alternatively, you could just change the loop to a while-loop and process the list from the start until it's empty: 或者,您可以将循环更改为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));

    }
}

When going with the second example, you might just as well use a Queue<T> instead of a List<T> for the conversations, as a queue is designed specifically with first-in, first-out access in mind. 在第二个示例中,您最好也使用Queue<T>而不是List<T>进行对话,因为队列是专门为先进先出访问而设计的。

If you dont have a business requirment to maintain order, then Always iterate the collection in reverse order when you are planning to remove items. 如果您没有维持订单的业务要求,则在计划删除项目时始终以相反的顺序迭代集合。 This you can remove items without breaking the sequence of the array. 这样,您可以删除项目而不会破坏数组的顺序。 So here 所以在这里

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

This method works in general for all the situations where we remove something from the collection. 通常,此方法适用于所有从集合中删除内容的情况。 However on a side note, Removing the conversation in Playconversation method is just a bad practice. 但是,顺便提一下,在Playconversation方法中删除对话只是一个不好的做法。 you will end up with hard to maintain code. 您最终将难以维护代码。 Remove it in some method which is specifically for this purpose. 用专门为此目的的某种方法将其删除。 otherwise you are violating SRP 否则,您违反了SRP

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM