Application.quit() produces ungraceful exit
I attached the following code to an invisible GameObject.
After Building and Running, pressing the "X" key causes the game to halt BUT the program is left in a "program not responding" state rather than closing gracefully. What else do i need to do to get a game exe to end gracefully?
platform: Windows 7 pro.... Unity 5.2.1 f1 64bit
void Update () {
if (Input.GetKey(KeyCode.X)) {
Debug.Log("X code Detected");
Application.Quit();
}
}
honestly not sure, but id guess something is left running that doesn't want to quit. so i would load an empty scene that has nothing in it but a script to quit as soon as it loads. this way everything that was running before will have been unloaded already and shouldn't interfere with the exiting.
Answer by memetic007 · Sep 24, 2015 at 04:25 PM
Ok, I figured it out:
My game launches a long running coroutine that sends messages to a process outside of Unity via NetMQ (the .Net version of zeroMQ which has a Unity compatible version).
Application.Quit() apparently DOESN'T stop the coroutine, or at least it doesn't do so gracefully. Stopping the coroutine prior to calling Application.Quit() appears to have fixed the problem.
As a note for possible future exploration StopCoroutine("MyCoroutine") didn't seem to successfully stop the coroutine, even though I had launched it with StartCoroutine("MyCouroutine"). Instead I had the coroutine monitoring a variable and terminating itself when the value of the variable changed. Not elegant, but it worked. I am curious why StopCoroutine didn't work.
This is a bit old, but the problem with coroutines can easily be avoided by defining the coroutine as a accessible parameter with a reference. Using a string as a reference to start a coroutine is to be avoided if the coroutine is long or looping.
A proper way of managing a coroutine so that you can properly stop it without any risk of loosing the reference is the following way:
public IEnumerator CoroutineInstance;
public void StartCoroutineInstance()
{
if(CoroutineInstance != null) {
StopCoroutine(CoroutineInstance);
CoroutineInstance = null;
}
CoroutineInstance = CoroutineName();
StartCoroutine(CoroutineInstance);
}
public void StopCoroutineInstance() {
if (CoroutineInstance != null)
{
StopCoroutine(CoroutineInstance);
CoroutineInstance = null;
}
}
public IEnumerator CoroutineName()
{
while (/*Whatever condition*/)
{
//Do whatever you need it to do.
yield return null;
}
}
In the code above, you can change the IEnumerator content to whatever you need. StartCoroutine(String); will start a coroutine based on the string. If you call it twice, the 1st coroutine reference toward the string gets lost which explains why StopCoroutine(String) might not stop the coroutine afterward. Without referring the Coroutine in its own parameter, the only way to stop a coroutine who losts its reference string link is to use StopAllCoroutine();
In the example above, the function called StartCoroutineInstance(), which can be named as you want, can includes parameters and so, if needed, you can easily create a loop enumerator like this:
public IEnumerator CoroutineInstance;
public void StartCoroutineInstance(bool islooping)
{
if(CoroutineInstance != null) {
StopCoroutine(CoroutineInstance);
CoroutineInstance = null;
}
CoroutineInstance = CoroutineName(islooping);
StartCoroutine(CoroutineInstance);
}
public void StopCoroutineInstance() {
if (CoroutineInstance != null)
{
StopCoroutine(CoroutineInstance);
CoroutineInstance = null;
}
}
public IEnumerator CoroutineName(bool isLooping)
{
if (isLooping)
{
while (isLooping)
{
//Do whatever you need it to do continuously.
yield return null;
}
}
else
{
// Do whatever you need it to do only ONC$$anonymous$$
yield return new WaitForSeconds(1f);
}
}