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