I have an array to instantiate multiple gameobjects when the player enters on a trigger but I don't know how to destroy these gameobjects when the player exits the trigger. This is my code:
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);
}
}
}
UPDATE CODE:
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));
}
}
}
Currently you don't store a reference to the instantiated gameobjects.
For this you can create another list and add the instantiated objects, something like this (this is a short version, you could also store them in a temp):
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));
}
}
And then for destroying:
for(int i = 0; i < instantiated.Count; i++)
{
Destroy(instantiated[i]);
}
There are other ways too. E.g. if you don't want to re-initialize the list every time, you can remove the items from the list before destroying them. In this case you need to iterate the list from back to front though. (Also, with the above, you must not try to reference something from the list if the objects were destroyed obviously, since this would raise an error.)
Another way would be to add the gameobjects as child to a certain parent upon instantiation and iterate them for destroying, something like
while(parentTransform.childCount > 0)
{
Transform child = parentTransform.GetChild(0);
Destroy(child.gameObject);
child.SetParent(null);
}
Iterate through the list to destroy each object, then create a new list where null objects are removed:
public List<GameObject> list;
foreach (GameObject item in list) { Destroy(item); }
list.RemoveAll(GameObject => GameObject == null); // or do list = new List<GameObject>();
Note, when removing null objects from a list you need to wait for the next frame for the object to actually be destroyed and become a null object in the list, so you could clean the list in an IEnumerator function a frame later, example script below:
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);
}
}
}
Related
My problem is that when all the enemies are killed the scene that should be loaded is not loading. I did add the scene to the Build setting (it has an index of 3) but it is still not loading. The script I created is attached to an empty object and not directly to the sprite (is that okay?). Can someone tell me why the scene isn't loading? Thank you.
This image is for to show you the EnemySpawner empty object inspector
EnemySpawner Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemySpawner : MonoBehaviour {
[SerializeField] GameObject EnemyPreFab;
[SerializeField] int MaxEnemies = 30;
[SerializeField] float EnemySpawnTime = 1.00001f;
[SerializeField] GameObject FirstWaypoint;
int CurrentNumOfEnemies = 0;
public LevelManager myLevelManager;
public int maximumnumberofhits = 0;
int timesEnemyHit;
IEnumerator SpawningEnemies()
{
while(CurrentNumOfEnemies <= MaxEnemies)
{
GameObject Enemy = Instantiate(EnemyPreFab, this.transform.position, Quaternion.identity);
CurrentNumOfEnemies++;
yield return new WaitForSeconds(EnemySpawnTime);
}
}
void Start()
{
StartCoroutine(SpawningEnemies());
timesEnemyHit = 0;
if (this.gameObject.tag == "EnemyHit")
{
CurrentNumOfEnemies++;
}
}
void OnCollisionEnter2D()
{
timesEnemyHit++;
if (timesEnemyHit == maximumnumberofhits)
{
CurrentNumOfEnemies--;
Destroy(this.gameObject);
}
if (CurrentNumOfEnemies == 0)
{
myLevelManager.LoadLevel("NextLevelMenu");
Debug.Log("LevelLoaded");
}
}
}
LevelManger script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour {
public void LoadLevel(string name)
{
print("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
}
EnemyShooting Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyShooting : MonoBehaviour {
[SerializeField] float EnemyLaserSpeed = 10f;
[SerializeField] float EnemyLaserFireTime;
[SerializeField] GameObject LaserBulletEnemyPreFab;
[SerializeField] int MaxNumberOfHits = 1;
int CurrentNumberOfHits = 0;
Coroutine FireCoroutine;
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject.tag == "PlayerLaser")
{
if(CurrentNumberOfHits < MaxNumberOfHits)
{
CurrentNumberOfHits++;
Destroy(collider.gameObject);
Score.ScoreValue += 2;//The user will be rewarded 1 point
}
}
}
void DestroyEnemy()
{
if(CurrentNumberOfHits >= MaxNumberOfHits)
{
Destroy(gameObject);
}
}
private void Fire()
{
FireCoroutine = StartCoroutine(ShootContinuously());
}
void BecomeVisible()
{
Fire();
}
IEnumerator ShootContinuously()
{
while (true)
{
GameObject LaserBulletEnemy = Instantiate(LaserBulletEnemyPreFab, this.transform.position, Quaternion.identity) as GameObject;
LaserBulletEnemy.GetComponent<Rigidbody2D>().velocity = new Vector2(0, EnemyLaserSpeed);
EnemyLaserFireTime = Random.Range(0.5f, 0.9f);
yield return new WaitForSeconds(EnemyLaserFireTime);
}
}
// Use this for initialization
void Start () {
BecomeVisible();
}
// Update is called once per frame
void Update () {
DestroyEnemy();
}
}
EnemyPathing script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyPathing : MonoBehaviour {
[SerializeField] List<Transform> WayPoints;
[SerializeField] float EnemyMovingSpeed = 5f;
int WayPointIndex = 0;
void EnemyMoving()
{
if (WayPointIndex <= WayPoints.Count - 1)
{
var TargetedPosition = WayPoints[WayPointIndex].transform.position; //The position of where the enemy needs to go
TargetedPosition.z = 0f;
var MoveThisFrame = EnemyMovingSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(this.transform.position, TargetedPosition, MoveThisFrame);
if(transform.position == TargetedPosition)
{
WayPointIndex++;
}
}
else
{
Destroy(gameObject);
}
}
// Use this for initialization
void Start () {
transform.position = WayPoints[WayPointIndex].transform.position;
}
// Update is called once per frame
void Update () {
EnemyMoving();
}
}
Problem
You're checking for collisions on the SPAWNER; when someone hits the Spawner it counts down enemies. But the Spawner doesn't have a collision box in the screenshot so it can never be hit. The Scene changing code can never be called.
So the game, based on the code, looks like this:
Spawn X enemies,
Hit the Spawner X times,
(Removed: Destroy the Spawner,)
Change scene.
I'm guessing this is conceptually incorrect and you actually want to check collisions on the spawned enemies, which will then count up the amount of destroyed enemies, and change the scene when they are all dead.
Solution
Conceptually, what you want is:
Spawn X enemies
Count up variable for every enemy
On Enemy death, count it down
When 0, change scene
So how do we code this?
Well, every enemy needs a reference to the object that holds the count. You can do this in several ways, when I personally do it I usually have just one spawner that is responsible for everyone so I make that one a Singleton, that can be references from anywhere:
EnemySpawner
public class EnemySpawner : MonoBehaviour
{
public static Spawner Instance = null;
int CurrentNumOfEnemies = 0;
// ... etc
void Start()
{
if (Instance == null)
Instance = this;
// Spawn enemies like you do already, CurrentNumOfEnemies++ for every spawned
}
public OnEnemyDeath() {
CurrentNumOfEnemies--;
if (CurrentNumOfEnemies < 1)
{
// You killed everyone, change scene:
LevelManager.LoadLevel("Your Level");
}
}
}
Enemy script (I don't know how your current code looks, but here's a minimal solution based on how I THINK your code looks):
void OnDestroy()
{
// This will run automatically when you run Destroy() on this gameObject
EnemySpawner.Instance.OnEnemyDeath(); // Tell the EnemySpawner that someone died
}
This will only work if you have exactly only ONE spawner. If you have multiple ones you will have to send a reference to the instance of its spawner to every spawned enemy. I can show you how to do ths too, if you wish.
Bonus content
LevelManager doesn't need to be on a GameObject, it can be static instead:
Remove the LevelManager script from any GameObject
Change your LevelManager code to this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class LevelManager
{
public static void LoadLevel(string name)
{
Debug.Log("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
}
Now you can use it from ANYWHERE, without needing to initialize a reference to any script or GameObject:
LevelManager.LoadLevel("My Level");
myLevelManager.LoadLevel("NextLevelMenu"); is never executed, because you destroy the object in the if-test above.
I am creating a laser defender game in unity and I have this problem where when I shoot the first enemy it takes me directly to the NextLevelMenu scene but I want it to load when all the enemies are killed(on this level I have 5 enemies to kill). I have been told that I need to send a reference to the instance of its spawner to every spawned enemy but I did not quite understand. Can someone help, please?
EnemySpawner Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemySpawner : MonoBehaviour {
[SerializeField] GameObject EnemyPreFab;
[SerializeField] int MaxEnemies = 30;
[SerializeField] float EnemySpawnTime = 1.00001f;
[SerializeField] GameObject FirstWaypoint;
int CurrentNumOfEnemies = 0;
public LevelManager myLevelManager;
public int maximumnumberofhits = 0;
public static EnemySpawner Instance = null;
int timesEnemyHit;
IEnumerator SpawningEnemies()
{
while(CurrentNumOfEnemies <= MaxEnemies)
{
GameObject Enemy = Instantiate(EnemyPreFab, this.transform.position, Quaternion.identity);
CurrentNumOfEnemies++;
yield return new WaitForSeconds(EnemySpawnTime);
}
}
void Start()
{
if (Instance == null)
Instance = this;
StartCoroutine(SpawningEnemies());
timesEnemyHit = 0;
if (this.gameObject.tag == "EnemyHit")
{
CurrentNumOfEnemies++;
}
}
public void OnEnemyDeath()
{
CurrentNumOfEnemies--;
if (CurrentNumOfEnemies < 1)
{
// You killed everyone, change scene:
LaserLevelManager.LoadLevel("NextLevelMenu");
}
}
}
EnemyShooting script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyShooting : MonoBehaviour {
[SerializeField] float EnemyLaserSpeed = 10f;
[SerializeField] float EnemyLaserFireTime;
[SerializeField] GameObject LaserBulletEnemyPreFab;
[SerializeField] int MaxNumberOfHits = 1;
int CurrentNumberOfHits = 0;
Coroutine FireCoroutine;
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject.tag == "PlayerLaser")
{
if(CurrentNumberOfHits < MaxNumberOfHits)
{
CurrentNumberOfHits++;
Destroy(collider.gameObject);
Score.ScoreValue += 2;//The user will be rewarded 1 point
}
}
}
void DestroyEnemy()
{
if(CurrentNumberOfHits >= MaxNumberOfHits)
{
Destroy(gameObject);
EnemySpawner.Instance.OnEnemyDeath(); // Tell the EnemySpawner that someone died
}
}
private void Fire()
{
FireCoroutine = StartCoroutine(ShootContinuously());
}
void BecomeVisible()
{
Fire();
}
IEnumerator ShootContinuously()
{
while (true)
{
GameObject LaserBulletEnemy = Instantiate(LaserBulletEnemyPreFab, this.transform.position, Quaternion.identity) as GameObject;
LaserBulletEnemy.GetComponent<Rigidbody2D>().velocity = new Vector2(0, EnemyLaserSpeed);
EnemyLaserFireTime = Random.Range(0.5f, 0.9f);
yield return new WaitForSeconds(EnemyLaserFireTime);
}
}
// Use this for initialization
void Start () {
BecomeVisible();
}
// Update is called once per frame
void Update () {
DestroyEnemy();
}
}
I would add a two fields to the spawner script. EnemiesToNextLevel and KilledEnemies. Then in the OnEnemyDeath() of your spawner, you may increase KilledEnemies everytime it is called, and then ask if KilledEnemies >= EnemiesToNextLevel, before changing the scene.
Sure there are a lot of other ways to do it, but for me thats the easiest.
I am trying to iterate through a list of GameObjects and find the first GameObject that is not active in the hierarchy and return that GameObject.
The problem I am having is my foreach statement keep returning null on "enemy"
"enemy" in this statement below is where the problem is
"GameObject enemy in pizzaEnemyList"
I do have one Gameobject inside of the list. Included in picture below
private List<GameObject> pizzaEnemyList = new List<GameObject> ();
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
int count = 0;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = pizzaEnemyList [count];
pizzaEnemyList.Remove (enemy);
return pizzaEnemy;
}
count += 1;
}
return pizzaEnemy;
}
//Function I am using to add the enemies to the list.
public void DeactivateAndStoreEnemy(GameObject enemy)
{
//decativates the enemy
enemy.SetActive(false);
//Store the enemy into the correct list
if (enemy.name == "PizzaGuy")
{
pizzaEnemyList.Add (enemy);
}
else if (enemy.name == "FiresGuy")
{
friesEnemyList.Add (enemy);
}
else if (enemy.name == "SodaGuy")
{
sodaEnemyList.Add (enemy);
}
}
public int PizzaListUnactiveEnemyCount()
{
int unactiveEnemiesCount = 0;
foreach (GameObject enemies in pizzaEnemyList)
{
if (enemies.activeInHierarchy == false)
{
unactiveEnemiesCount += 1;
}
}
return unactiveEnemiesCount;
}
I have tested your code and can tell you it works if the gameObject are added properly and that they are actually not active.
Your problem is most probably not adding the game objects correctly to the list and maybe also not making sure that pizzaEnemyList has at least 1 item that is set inactive. When all item are active in your list its normal that it returns null because it will never go in if (enemy.activeInHierarchy == false)
It would be better if you had a public List<GameObject> pizzaEnemyList; that you setup in the inspector of unity. Unless if this solution doesn't fit with the game you're building.
As Serlite said you don't need to keep a counter when using foreach, your code could look like this :
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = enemy;
pizzaEnemyList.Remove(enemy);
return pizzaEnemy;
}
}
return pizzaEnemy;
}
Edit after your edit:
I've tested your code with this and it works :
private List<GameObject> pizzaEnemyList = new List<GameObject>();
void Start()
{
GameObject pizzaGuy = GameObject.Find("PizzaGuy");
DeactivateAndStoreEnemy(pizzaGuy);
Debug.Log(FetchPizzaEnemy());
}
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = enemy;
pizzaEnemyList.Remove(enemy);
return pizzaEnemy;
}
}
return pizzaEnemy;
}
public void DeactivateAndStoreEnemy(GameObject enemy)
{
enemy.name = "PizzaGuy";
//decativates the enemy
enemy.SetActive(false);
//Store the enemy into the correct list
if (enemy.name == "PizzaGuy")
{
pizzaEnemyList.Add(enemy);
}
}
I have a gameobject named PizzaGuy in my scene.
I have items appearing on four spawn locations. When I remove one and it gets destroyed. I want a new item to appear on the spawn point that the item came from.
Creating the first 4 items
public class ItemManager : MonoBehaviour {
public GameObject Item;
private float spawnTime = 3f;
public Transform[] spawnPoints;
static public int spawnPointIndex;
// Use this for initialization
void Start () {
for(int i = 0; i < spawnPoints.Length; i++)
{
spawnPointIndex = i;
Instantiate(Item, spawnPoints[spawnPointIndex].position,spawnPoints[spawnPointIndex].rotation);
}
}
}
I stripped the code. This allows to destroy the object when a condition is met.
Note: This is on a PreFab GameObject
public class ItemController : MonoBehaviour {
public int spawnLocation;
void Start()
{
spawnLocation = ItemManager.spawnPointIndex;
}
void DestroyObject()
{
if (whenConditionIsTrue == true){
Destroy(this.gameObject);
//Invoke new item based on spawn Location
}
ObjectMouseDown = false;
}
}
This is as far as I have got. I don't quite understand how to get the spawnLocation back to the ItemManager in order to Instatiate a new Item.
Thanks!
Below is a commented and tested script you should find useful. Once an item is destroyed, it spawns a new item to the same point after spawnTime seconds. I implemented the delay so that you can actually see the script working.
using System.Collections;
using UnityEngine;
public class ItemManager : MonoBehaviour
{
public ItemController Item;
public Transform[] spawnPoints;
private float spawnTime = 3f;
void Start()
{
foreach (Transform spawnPoint in spawnPoints)
{
StartCoroutine(Spawn(spawnPoint)); // Spawn is implemented as a coroutine, so that a delay can be added
}
}
IEnumerator Spawn(Transform spawnPoint)
{
yield return new WaitForSeconds(spawnTime); // See "Coroutines" in Unity documentation
ItemController newItem = Instantiate(Item, spawnPoint.position, spawnPoint.rotation);
newItem.OnDestroy += () => { StartCoroutine(Spawn(spawnPoint)); }; // Subscribe to the OnDestroy event. When it occurs, run the Spawn coroutine again.
}
}
using System;
using UnityEngine;
public class ItemController : MonoBehaviour
{
public event Action OnDestroy;
void DestroyObject ()
{
Destroy(gameObject);
if (OnDestroy != null) OnDestroy(); // OnDestroy is null if there are no subscribers
}
void OnMouseDown () // For testing. Unity calls this method when a collider on this gameObject is clicked
{
DestroyObject();
}
}
What I would do here is have an event on ItemController that gets fired when it gets destroyed. The ItemManager can listen for these and handle them.
so for the ItemManager class, just listen and handle the event:
public class ItemManager : MonoBehaviour {
public GameObject Item;
private float spawnTime = 3f;
public Transform[] spawnPoints;
static public int spawnPointIndex;
void Start () {
for(int i = 0; i < spawnPoints.Length; i++)
{
spawnPointIndex = i;
GameObject itemObject = Instantiate(Item, spawnPoints[spawnPointIndex].position,spawnPoints[spawnPointIndex].rotation);
itemObject.GetComponent<ItemController>().OnDestroy += SpawnNewItem;
}
}
public void SpawnNewItem(int i) {
//spawn new item at index i
}
}
and in the ItemController class, call the event with the relevant info
public class ItemController : MonoBehaviour {
public int spawnLocation;
public event System.Action<int> OnDestroy;
void Start()
{
spawnLocation = ItemManager.spawnPointIndex;
}
void DestroyObject()
{
if (whenConditionIsTrue == true){
Destroy(this.gameObject);
OnDestroy(this.spawnLocation);
}
ObjectMouseDown = false;
}
}
this pattern keeps them uncoupled which is what I like when using managers.
I want to instantiate 3 gameobjects in 3 positions of a list of 20 random positions. When I play the game it’s instantiating 20 gameobjects in 20 positions, and not 3 gameobjects. How can I do it? This is my code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpawnManager: MonoBehaviour {
private GameObject Player;
public List<GameObject> spawnPositions;
public List<GameObject> spawnObjects;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
SpawnObjects ();
}
}
void SpawnObjects()
{
foreach (GameObject spawnPosition in spawnPositions)
{
int selection = Random.Range (0, spawnObjects.Count);
Instantiate (spawnObjects [selection], spawnPosition.transform.position, spawnPosition.transform.rotation);
}
}
}
UPDATE:
Sometimes 2 objects are placed in the same position and I want the objects to instantiate in different positions. I've tried to add the random positions to a list and only instantiate if it isn't already in the list, but it doesn't work. This is my code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpawnManager : MonoBehaviour {
private GameObject Player;
public List<GameObject> spawnPositions;
public List<GameObject> spawnObjects;
private GameObject obj;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
SpawnObjects ();
}
}
void SpawnObjects()
{
for (int i = 0; i < 3; ++i)
{
int randomObject = Random.Range(0, spawnObjects.Count);
int randomPosition = Random.Range(0, spawnPositions.Count);
List <GameObject> _spawnPositions = new List<GameObject>();
obj = spawnPositions[randomPosition];
_spawnPositions.Add(obj);
if (!_spawnPositions.Contains (obj))
{
Instantiate (spawnObjects [randomObject], _spawnPositions [randomPosition].transform.position, _spawnPositions [randomPosition].transform.rotation);
}
else
{
Debug.Log ("error");
}
}
}
}
You're looping over all of the positions and adding random objects to them, you need to randomise that as well. So this:
foreach (GameObject spawnPosition in spawnPositions)
{
int selection = Random.Range (0, spawnObjects.Count);
Instantiate (spawnObjects [selection], spawnPosition.transform.position, spawnPosition.transform.rotation);
}
Should be this:
int randomObject = Random.Range(0, spawnPositions.Count);
int randomPosition = Random.Range(0, spawnPositions.Count);
Instantiate (spawnObjects[randomObject], spawnPositions[randomPosition].transform.position, spawnPositions[randomPosition].transform.rotation);
And then just put that in a for loop like:
for (int i = 0; i < 3; ++i)
In your updated code you're creating the list on each loop, you need to use the same list (untested but should work):
List<int> randomObjects = new List<int>();
List<int> randomPositions = new List<int>();
for (int i = 0; i < 3; ++i)
{
int randomObject;
do
{
randomObject = Random.Range(0, spawnObjects.Count);
}
while (randomObjects.Contains(randomObject));
randomObjects.Add(randomObject);
int randomPosition;
do
{
randomPosition = Random.Range(0, spawnPositions.Count);
}
while (randomPositions.Contains(randomPosition));
randomPositions.Add(randomPosition);
Instantiate(spawnObjects[randomObject], spawnPositions[randomPosition].transform.position, spawnPositions[randomPosition].transform.rotation);
}