Уничтожить игровые объекты массива

#c# #unity3d #unity5

#c# #unity3d

Вопрос:

У меня есть массив для создания нескольких игровых объектов, когда игрок вводит триггер, но я не знаю, как уничтожить эти игровые объекты, когда игрок выходит из триггера. Это мой код:

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

public class SpawnDestroy : MonoBehaviour {

public List<GameObject> spawnPositions;
public List<GameObject> spawnObjects;


void OnTriggerEnter(Collider other)
{

    if (other.gameObject.tag == "Player")
    {
        SpawnObjects ();
    }
}

void OnTriggerExit(Collider other)
{

    if (other.gameObject.tag == "Player")
    {

    ............

    }
}

void SpawnObjects()
{
    foreach(GameObject spawnPosition in spawnPositions)
    {
        int selection = Random.Range(0, spawnObjects.Count);
        Instantiate(spawnObjects[selection], spawnPosition.transform.position, spawnPosition.transform.rotation);
    }
}

}
  

ОБНОВИТЬ КОД:

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


public class SpawnDestroy : MonoBehaviour {

public List<GameObject> spawnPositions;
public List<GameObject> spawnObjects;
private List<GameObject> instantiated;


void OnTriggerEnter(Collider other)
{

    if (other.gameObject.tag == "Player")
    {
        SpawnObjects ();
    }
}

void OnTriggerExit(Collider other)
{

    if (other.gameObject.tag == "Player")
    {

        for(int i = 0; i < instantiated.Count; i  )
        {
            Destroy(instantiated[i]);
        }

        }
}

void SpawnObjects()
{
    // (re-)initialize as empty list
    instantiated = new List<GameObject>();

    foreach(GameObject spawnPosition in spawnPositions)
    {
        int selection = Random.Range(0, spawnObjects.Count);
        instantiated.Add(Instantiate(spawnObjects[selection], spawnPosition.transform.position, spawnPosition.transform.rotation));
    }
}

}
  

Ответ №1:

В настоящее время вы не сохраняете ссылку на созданные игровые объекты.

Для этого вы можете создать другой список и добавить созданные объекты, что-то вроде этого (это сокращенная версия, вы также можете сохранить их во временном режиме):

 private List<GameObject> instantiated;

...

void SpawnObjects()
{
    // (re-)initialize as empty list
    instantiated = new List<GameObject>();

    foreach(GameObject spawnPosition in spawnPositions)
    {
        int selection = Random.Range(0, spawnObjects.Count);
        instantiated.Add((GameObject)Instantiate(spawnObjects[selection], spawnPosition.transform.position, spawnPosition.transform.rotation));
    }
}
  

А затем для уничтожения:

 for(int i = 0; i < instantiated.Count; i  )
{
    Destroy(instantiated[i]);
}
  

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

Другим способом было бы добавить игровые объекты как дочерние к определенному родительскому элементу при создании экземпляра и повторить их для уничтожения, что-то вроде

 while(parentTransform.childCount > 0)
{
    Transform child = parentTransform.GetChild(0);
    Destroy(child.gameObject);
    child.SetParent(null);
}
  

Комментарии:

1. Несмотря на то, что мне это нравится, я думаю, что здесь опечатка. instantiated.Add(Instantiate(spawnObjects[selection], spawnPosition.transform.position, spawnPosition.transform.rotation)); должно быть instantiated.Add(Instantiate(prefab, spawnPosition.transform.position, spawnPosition.transform.rotation));

2. @Programmer Я думаю, spawnObjects предполагается, что это список префабов. Если нет, это, конечно, нужно изменить.

3. @GunnarB. Я протестировал это, и появились следующие ошибки: Assets/0_asm/Scripts /SpawnDestroy.cs(44,38): ошибка CS1502: наилучшее соответствие перегруженного метода для System.Collections.Generic.List<UnityEngine.GameObject>.Add(UnityEngine.GameObject)' has some invalid arguments Assets/0_asm/Scripts/SpawnDestroy.cs(44,38): error CS1503: Argument # 1′ не может преобразовать UnityEngine.Object' expression to type UnityEngine. Игровой объект’

4. О, да, я виноват. Возврат Instantiate должен быть приведен к GameObject путем добавления (GameObject) перед созданным экземпляром. Я отредактировал это.

5. @GunnarB. У меня ошибка, потому что игрок подбирает некоторые объекты перед выходом из триггера. Как я могу это решить?

Ответ №2:

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

 public List<GameObject> list;    
foreach (GameObject item in list) { Destroy(item); }
list.RemoveAll(GameObject => GameObject == null); // or do list = new List<GameObject>();
  

Обратите внимание, что при удалении нулевых объектов из списка вам нужно дождаться следующего кадра, чтобы объект действительно был уничтожен и стал нулевым объектом в списке, чтобы вы могли очистить список в функции IEnumerator кадром позже, пример сценария ниже:

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;    
public class ListCLeaner: MonoBehaviour
{
    public List<GameObject> list;    
    public void ClearList(){
        foreach (GameObject item in list) { Destroy(item); }
        StartCoroutine(CleanListAfterFrame());
    }
    IEnumerator CleanListAfterFrame(){
        yield return new WaitForEndOfFrame();
        list.RemoveAll(GameObject => GameObject == null);
    }
}
  

}