I'm having a bit of trouble with this script. It gathers everything I need to consider while respawning, then goes through some tests and respawns. Now I'm trying to get the spawning to slow between pieces. Before I've had success using Code (CSharp): yield return new WaitForSeconds(x); Unfortunately that only seems to work in a CoRoutine. I've also given Invoke and InvokeRepeating a try. I can't seem to get either to work. Here is the current state of my code. It dumps a ton of new game pieces all at once. Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; public class Respawner : MonoBehaviour { //Each Spawn Point Game Object Linked to these for testing purposes public int intS1 = 0; //variables to load from SpawnPieces public GameObject Spawner; public float fSpawnDelay; public int maxPieces; public List<GameObject> MasterSpawn = new List<GameObject>(); //variables to load from GamePlay public List<GameObject> selectedObj = new List<GameObject>(); //holds game objects public List<GameObject> SpawnList = new List<GameObject>(); //Tracks the spawn points selected public GameObject track; //gets the value of current object public bool click = false; //used to track whether the mouse was clicked public bool click2 = true; //used to track second click private bool RisSelected; //tracks respawn #region GetComponents - Loads all the pieces necessary from other scripts (Loads on Awake) void GetComponents() { //Get Needed Components from SpawnPieces SpawnPieces spawnLoad = GetComponent<SpawnPieces>(); //Spawner = spawnLoad.Spawner; fSpawnDelay = spawnLoad.fSpawnDelay; maxPieces = spawnLoad.maxPieces; MasterSpawn = spawnLoad.MasterSpawn; //Get Needed Components from GamePlay GamePlay gamePlay = FindObjectOfType<GamePlay>(); selectedObj = gamePlay.selectedObj; } #endregion #region ReSpawner Gather - Tests for Respawn void ReSpawnerGather() { foreach(GameObject x in selectedObj) { //Load values from Piecscore.cs PieceScore select = x.GetComponent<PieceScore>(); //Get value of current selected piece RisSelected = select.RisSelected; //Load Values from Spawn Tracker var t = x.GetComponent<SpawnTracker>(); //Get Spawn ID track = t.spawnID; if(RisSelected == false) { //increment value of how many pieces are needed. intS1 ++; //add tracker to the list SpawnList.Add(track); //turn on the selector so it is selected only once select.RisSelected = true; } } } #endregion void ReSpawn() { foreach(GameObject x in SpawnList) { if(x == Spawner) { for(int i=0; i<intS1; i++) { int randomSpwn = Random.Range(0, MasterSpawn.Count); Instantiate(MasterSpawn[randomSpwn], Spawner.transform.position, Quaternion.identity); } } else { PieceScore selectcl = x.GetComponent<PieceScore>(); selectcl.RisSelected = false; } } } #region SpawnPieces - Spawns pieces IEnumerator SpawnPieces() { ReSpawnerGather(); ReSpawn(); yield return new WaitForSeconds(fSpawnDelay); EmptyValues(); } #endregion #region ClickEvent - Mouse Controls for the respawn (Made to mimic GamePlay Class); void ClickEvent() { if (Input.GetMouseButtonDown(0)) { //Debug.Log ("Clicked"); click = !click; click2 = !click2; } if (click == true) { } else if (click2 == true) { //ReSpawnerGather(); StartCoroutine(SpawnPieces()); } else { } } #endregion #region Empty Values - Resets variables for retesting void EmptyValues() { //Empty all values to set up for another test intS1 = 0; SpawnList.Clear(); } #endregion void Awake() { GetComponents(); } // Use this for initialization void Start () { } // Update is called once per frame void Update () { ClickEvent(); } } I do suspect that it has something to do with being on Update. I try to increment a value "intS1 ++" which does collect the correct number of pieces that I need to respawn. I just can't figure out how to make only that amount spawn.
Ok new approach. Yet again the Update function is my enemy. So I now have removed most of the code and basically started all over. And it still just won't work. So the idea is to grab the entire game object list from another class and on click I'm taking each piece from that list, accessing a component (which contains the game object that piece was spawned from) into another list called Spawnlist. That works. The next thing I needed to do was take the list of those game objects and see how many times a specific object is contained within that list. Naturally I thought something like: Code (CSharp): int checkSpawnList() { foreach(GameObject x in SpawnList) { PieceScore select = x.GetComponent<PieceScore>(); //Get value of current selected piece SisSelected = select.SisSelected; if(x == Spawner && SisSelected == false) { if(SisSelected == false) { Debug.Log ("The Update Function hates me"); intS1 ++; SisSelected = true; } } } return intS1; } Well the problem is that intS1 will not increment. No matter what I do. I need this to increment so I have a base for how many pieces need to be respawned. Well, one victory at a time. Here is my current full code: Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; public class Respawner : MonoBehaviour { //Each Spawn Point Game Object Linked to these for testing purposes public int intS1 = 0; //variables to load from SpawnPieces public GameObject Spawner; public float fSpawnDelay; public int maxPieces; public List<GameObject> MasterSpawn = new List<GameObject>(); //variables to load from GamePlay public List<GameObject> selectedObj = new List<GameObject>(); //holds game objects public List<GameObject> SpawnList = new List<GameObject>(); //Tracks the spawn points selected public GameObject track; //gets the value of current object public bool click = false; //used to track whether the mouse was clicked public bool click2 = true; //used to track second click private bool RisSelected; //tracks respawn private bool SisSelected; //tracks respawn #region GetComponents - Loads all the pieces necessary from other scripts (Loads on Awake) void GetComponents() { //Get Needed Components from SpawnPieces SpawnPieces spawnLoad = GetComponent<SpawnPieces>(); //Spawner = spawnLoad.Spawner; fSpawnDelay = spawnLoad.fSpawnDelay; maxPieces = spawnLoad.maxPieces; MasterSpawn = spawnLoad.MasterSpawn; //Get Needed Components from GamePlay GamePlay gamePlay = FindObjectOfType<GamePlay>(); selectedObj = gamePlay.selectedObj; } #endregion #region ReSpawner Gather - Tests for Respawn and Builds SpawnList void ReSpawnerGather() { foreach(GameObject x in selectedObj) { //Load values from Piecscore.cs PieceScore select = x.GetComponent<PieceScore>(); //Get value of current selected piece RisSelected = select.RisSelected; //Load Values from Spawn Tracker var t = x.GetComponent<SpawnTracker>(); //Get Spawn ID track = t.spawnID; if(RisSelected == false) { //add tracker to the list SpawnList.Add(track); //change selected to true RisSelected = true; } } } #endregion int checkSpawnList() { foreach(GameObject x in SpawnList) { PieceScore select = x.GetComponent<PieceScore>(); //Get value of current selected piece SisSelected = select.SisSelected; if(x == Spawner) { if(SisSelected == false) { Debug.Log ("The Update Function hates me"); intS1 ++; SisSelected = true; } } } return intS1; } #region ClickEvent - Mouse Controls for the respawn (Made to mimic GamePlay Class); void ClickEvent() { if (Input.GetMouseButtonDown(0)) { //Debug.Log ("Clicked"); click = !click; click2 = !click2; } if (click == true) { } else if (click2 == true) { ReSpawnerGather(); checkSpawnList(); } } #endregion void Awake() { GetComponents(); } // Use this for initialization void Start () { } // Update is called once per frame void Update () { ClickEvent(); } }
Since disabled scripts and/or non-active game objects so not get their update or other co routines run, you may want to consider a different pattern/approach. One nice universal clean respawn pattern I like is to make a new game object with a generic respawn script on it, and a public GameObject field to who you want to reenable, or instantiate. Then when it fires, it activates the target to respawn, then it destroys itself. When you want another respawn, lather rinse repeat, making a fresh respawner.
Hmm that could work. I'm going to have to try that later tonight. Since each GameObject already contains the value for the spawner it came from, maybe something as simple as having it spawn from that same point if the game object is destroyed. I'll keep at it. I'm going to get this to work.
I have a question on spawning. Is it possible to make the spawn point absolutely random on any point of the floor ? I would like to make a random number of enemies appear on any random point of the entire floor.
Yeah it should be. You would need to put a Random.Range on the Vector3 position part of the Instantiate line. If you look at this part of my initial script: Code (CSharp): int randomSpwn = Random.Range(0, MasterSpawn.Count); Instantiate(MasterSpawn[randomSpwn], Spawner.transform.position, Quaternion.identity); I'm using a Random.Range to generate a random piece to spawn (from a list called MasterSpawn). Next to that is Spawner.transform.position. This is where it would actually spawn from. One note, Spawner is a variable I already preset to be a GameObject. It is grabbing the position information of that game object. If you set up a Random there, you would be able to make them instantiate on a random location. One thing you would have to mitigate is the actual range it would be able to spawn from. You probably don't want enemies falling from the sky or being created below your terrain. I'd setup a list of possible spawn points (just a lot of them to appear very random within your world) and then Randomly instantiate to that location from that list. Hope that helps.
Well I figured out what I was doing wrong on the script. I was actually losing the list of game objects that I needed to test. I think I should have it worked out in a day or two.