- Home /
Trouble Resuming after Yielding while Inside Coroutine
Hello everyone, I'm having trouble with yielding for a coroutine (then resuming execution) while inside another coroutine, where yielding to another coroutine causes the original coroutine to never complete (it just ends after the yield instuction. More details below:
The Script:
private IEnumerator InitialSpawnLogic()
{
Debug.Log("InitialSpawnLogic() coroutine starting...");
#region Dealing with Initial Spawning:
//figure out if a player/npc are needed or some other combo:
//we always need a player ship:
yield return StartCoroutine(ChooseSpawnAndInstantiateShip(currentPlayerShip, false) ); //select a good spawn point, instantiate Player...
//need an NPC ship unless TRAINING is detected:
if(currentGameMode != GameModes.Training)
{
Debug.Log("the GAMEMODE seleteced requires at least 1 NPC ship...");
//now get NPC:
Debug.Log("1111");
yield return StartCoroutine (ChooseSpawnAndInstantiateShip(currentNPCShip, true) ); //select a good spawn point, instantiate NPC..
Debug.Log("2222");
}
else
{
Debug.Log("the GAMEMODE seleteced does NOT require any NPC ship(s)...");
}
#endregion Dealing with Initial Spawning:
Debug.Log("3333");
//check game type to either start recurring spawn logic or not:
if(currentGameMode == GameModes.Survival) //for now, RANDOM is only 1v1 battles (since that is the "free default", so don't account for it)...
{
Debug.Log("currentGameMode == GameModes.Survival");
StartCoroutine("RecurringSpawnLogic");
}
else
{
Debug.Log("This game type does not require Re-spawns, InitialSpawnLogic() coroutine ending");
}
}
In Detail:
The InitialSpawnLogic coroutine never gets to the "Debug("2222")" line or beyond. What confuses me is that there does not seem to be any problem the first time I yield, and the method it yields to ends the same way regardless of the arguments passed in. So, why does the script continue to execute the first time but not the second?
Any ideas are appreciated, thank you for reading.
UPDATE 2: Turns out an issue with Nav Meshes on the created ships was stalling the script, problem fixed.
UPDATE: (as requested, here are the other methods in question)
//get valid spawn point, then instantiate Ship:
private IEnumerator ChooseSpawnAndInstantiateShip(ShipTypes desiredShipType, bool isNPCShip)
{
Debug.Log("ChooseSpawnAndInstantiateShip() coroutine started...");
yield return StartCoroutine(GetSpawnPoint() ); //grab a valid spawn point for the incoming ship...
Debug.Log("valid spawn point found for new ship...");
GameObject ship; //becomes the instantiated prefab...
if(isNPCShip)
{
//create a new GO parent of the instan.GO, attatch the script to it (so the prefab can get NPC/Player controll):
GameObject npcShipGOParent = new GameObject();
npcShipGOParent.name = "NPCShip";
npcShipGOParent.transform.parent = parent_NPCShips;
Ship_ControlSetter sCS = npcShipGOParent.AddComponent<Ship_ControlSetter>();
sCS.ShipControlledBy = ShipControlledBy.NPC;
//Debug.Log("Manager_ShipSpawning: ChooseSpawnAndInstantiateShip() Breaking");
//Debug.Break();
//instantiate ship at spawn point:
if(desiredShipType != 0) //random ship desired...
{
ship = (GameObject) Instantiate(shipArray[(int) desiredShipType], tempSpawnLocation, Quaternion.identity);
Debug.Log("new NPC ship of value: " + (int) desiredShipType + " should have been instantiated");
ship.transform.parent = npcShipGOParent.transform;
}
else //random ship is desired:
{
ship = (GameObject) Instantiate(shipArray[Random.Range(1, shipArray.Length)], tempSpawnLocation, Quaternion.identity); //1 because of enum values...
Debug.Log("new randomized NPC ship should have been instantiated");
ship.transform.parent = npcShipGOParent.transform;
}
}
else //Player ship...
{
//create a new GO parent of the instan.GO, attatch the script to it (so the prefab can get NPC/Player controll):
GameObject playerShipGOParent = new GameObject();
playerShipGOParent.name = "PlayerShip";
playerShipGOParent.transform.parent = parent_PlayerShips;
Ship_ControlSetter sCS = playerShipGOParent.AddComponent<Ship_ControlSetter>();
sCS.ShipControlledBy = ShipControlledBy.Player;
//Debug.Log("Manager_ShipSpawning: ChooseSpawnAndInstantiateShip() Breaking");
//Debug.Break();
//instantiate the player ship at the chosen spawn point:
if(desiredShipType != 0) //specific ship desired...
{
ship = (GameObject) Instantiate(shipArray[(int) desiredShipType], tempSpawnLocation, Quaternion.identity);
Debug.Log("new Player ship of value: " + (int) desiredShipType + " should have been instantiated");
ship.transform.parent = playerShipGOParent.transform;
}
else //random ship is desired:
{
ship = (GameObject) Instantiate(shipArray[Random.Range(1, shipArray.Length)], tempSpawnLocation, Quaternion.identity); //1 because of enum values...
Debug.Log("new randomized Player ship should have been instantiated");
ship.transform.parent = playerShipGOParent.transform;
}
#region set ship correctly for Player Usage:
//the pathfinding GO and and NPC logic script need to get disabled/turned off:
Debug.Log("Manager_ShipSpawning disabling NPC components for Player Ship use...");
Transform pathfindingTrans = ship.transform.FindChild("Pathfinder");
pathfindingTrans.gameObject.GetComponent<NavMeshAgent>().enabled = false;
pathfindingTrans.gameObject.SetActive(false);
ship.GetComponentInChildren<NPC_Logic>().enabled = false;
//Debug.Log("ship.GetComponentInChildren<NPC_Logic>().enabled = false");
#endregion set ship correctly for Player Usage:
}
#region Final Setups for NPC/Player ships:
Ship_Initializer shipInitializer = ship.GetComponentInChildren<Ship_Initializer>();
shipInitializer.SetupShip();
UI_ObjectTracker.ui_ObjectTracker.Activate();
#endregion Final Setups for NPC/Player ships:
yield return null; //wait to make sure 2 ships don't get spawned on top of each other in the same frame...
}
//use this to effectively "lock up" Instantiation coroutines if no new spawn point is available:
private IEnumerator GetSpawnPoint()
{
Debug.Log("GetSpawnPoint() coroutine started");
//get valid spawn point:
while(true)
{
Debug.Log("GetSpawnPoint() coroutine running...");
tempSpawnLocation = spawnTransList[Random.Range(0, spawnTransList.Count)].transform.position;
Debug.Log("tempSpawnLocation is: " + tempSpawnLocation);
//Debug.Log("Manager_ShipSpawning: GetSpawnPoint() breaking");
//Debug.Break();
//now test to see if the spawnpoint is valid:
if(!Physics.CheckSphere(tempSpawnLocation, spawnSafeRadius, layersToCheckAgainst) ) //if nothing is hit in layermask...
{
//Debug.Log("ManagerShipSpawning: GetSpawnPoint() breaking");
//Debug.Break();
yield break;
}
else
{
Debug.Log("randomly selected spawnpoint was not valid, trying again...");
yield return new WaitForSeconds(1f); //done to minimize collider checks per frame...
}
}
}
Post Updated. I'm guessing based on your request that there isn't something obviously wrong with the first coroutine, so I'm messing something up in one/both of the others?
I suspect that the problem is in the while(true) loop inside the IEnumerator GetSpawnPoint(). I think that neither yield break; nor yield return new WaitForSeconds(1f); will actually end the while(true) loop, which will just endlessly keep yielding either break or WaitForSeconds.
So, it seems that the coroutine cannot be started a second time in line 19, because it's still running.
Yeah, that'll be it. The yield is preventing the break from actually doing its job.
It won't stop the coroutine from starting a second time though. You can have as many instances of a coroutine going as you want. In this case, you'll slowly leak memory indefinitely because none of them can finish.
Actually in one of my apps, if I tried to start the same coroutine more than once, I didn't have the expected results. Sometimes it would start, sometimes it wouldn't. So I prefer to avoid going that way.
Answer by SilentSin · Jan 24, 2015 at 04:20 AM
Put some logs into ChooseSpawnAndInstantiateShip to see where its actually getting to. Maybe yield return StartCoroutine(GetSpawnPoint()); isn't returning or something.
Also, in GetSpawnPoint you don't need to yield break, you can just break. A coroutine needs to have at least one yield in it, but it doesn't actually need to get called in every code path.
Thank you for the tip on the yield. Turns out that a warning related to Nav $$anonymous$$eshes on the instantiated ships was preventing the other coroutines from executing properly, once that was resolved everything worked as expected.
Your answer
Follow this Question
Related Questions
Coroutines and states 1 Answer
Wait for Coroutine without yield? (C#) 1 Answer
What is wrong with this use of WaitForSeconds? 1 Answer
Yield not working properly 1 Answer
C# - Coroutines for Abilities 1 Answer