Search Unity

This Script causes my Unity to crash.

Discussion in 'Scripting' started by phayezer, May 21, 2015.

  1. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    Hello all, I am having a bit of trouble with the attached script. Whenever I try to run my game, my Unity crashes, only stoppable via task manager. I BELIEVE there is a infinite loop somewhere, but I either cannot find it, or am wrong.

    Any help would be appreciated, since I cannot move on until I fix this.

    Thank you so much,

    Perry Hayes
     

    Attached Files:

  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Your infinite loop is your while loop in the Update. This is stemming from a misunderstanding of how Update works; you don't have game loops within it. Update is called once a frame.

    If you want to control your game that way, you need to do two things:
    a) move that loop into an IEnumerator function, which gets started from Start() (as you have done with spawnwaves).
    b) within your while loop, add 'yield return null;'. This will make the script stop there, wait for one frame, then come back and pick up at that point the next frame.
     
    Kiwasi and Ryiah like this.
  3. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    Thank you, that worked.

    good morning!
     
  4. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    Actually, I thought it did, but apparently, I have a new error: Update() cannot be a coroutine. Help!
     
  5. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    Never mind, i got that, but once I start the game, it works for a split second, then everything is deleted. new code attached.
     

    Attached Files:

  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I highly recommend you quit trying to use coroutines. They're usually just a crutch, but a confusing one that causes more grief than they save (at least among beginners).

    Much better to just embrace the fact that Update gets called once per frame, and design your code to work that way.

    Instead of attaching code, could you please insert it in your post using the CODE tags? I've already downloaded one attachment and I'm not going to bother with another, but to illustrate my point, here's your original Update method:
    Code (CSharp):
    1.     void Update ()
    2.     {
    3.         bool intro = false;
    4.         while (intro == false)
    5.         {
    6.             if(Input.GetButton("Fire1"))
    7.             {
    8.                 Application.LoadLevel("main");
    9.                 intro  = true;
    10.             }
    11.         }
    12.         StartCoroutine (spawnwaves());
    13.     }
    OK, so I believe the intent of this code is: when the Fire1 button is pressed, load the Main level, but only do this once. Just make "intro" into a property rather than a local variable, and this is easy to write correctly:

    Code (CSharp):
    1.     bool intro = false;
    2.     void Update () {
    3.         if (!intro && Input.GetButton("Fire1")) {
    4.             Application.LoadLevel("main");
    5.             intro  = true;
    6.         }
    7.     }
    Your original code also appeared to be trying to call StartCoroutine(spawnwaves()) after intro becomes true, but that would never work, because by that point you've already called Application.LoadLevel, which pretty much means "kill everything in memory and start over with the specified scene." (The exception would be if you had called DontDestroyOnLoad on this object, but I doubt that.)

    If your intent is to spawn stuff in the newly loaded scene, then you should do that in the start method of some object in that scene. Again, you will probably reach for a coroutine first, since I think you're coming from a procedural programming background, but it's not necessary... but let's cross that bridge when we come to it!
     
    NomadKing likes this.
  7. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    ok, so i have applied your advice, and now, when i start the game, the intro scene loads, then immediately deletes everything after about half a second. screenshot's attached.
     

    Attached Files:

  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Please describe in more detail what you've done. Use the "Insert" button (between the movie frames and the floppy disk icon) to insert relevant bits of code.

    Ideally, first isolate what's causing things to be deleted by disabling components (or entire game objects) one by one until you find the one responsible.
     
  9. phayezer

    phayezer

    Joined:
    Apr 17, 2015
    Posts:
    13
    it is in my game controller script game object. I figured it was in my game controller script, but I could not be certain until now. code pertaining to the scene switch below. the "intro" string is the screen i want to switch FROM, and the "main" string is the screen i want to switch TO.
    Code (CSharp):
    1. void Start ()
    2.     {
    3.         Application.LoadLevel("intro");
    4.         //StartCoroutine (game_start());
    5.     }
    6.     void Update ()
    7.     {
    8.         intro = false;
    9.         if (!intro && Input.GetButton("Fire1"))
    10.         {
    11.             Application.LoadLevel("main");
    12.             intro  = true;
    13.         }
    14.         StartCoroutine (spawnwaves());
    15.     }
    16.  
    17.     //IEnumerator game_start ()
    18.     //{
    19.         /*intro = false;
    20.         if(Input.GetButton("Fire1"))
    21.         {
    22.             Application.LoadLevel("main");
    23.             intro  = true;
    24.         }
    25.         yield return null;
    26.         */
    27.         //if (!intro && Input.GetButton("Fire1")) {
    28.             //Application.LoadLevel("main");
    29.             //intro  = true;
    30.     //}
     
  10. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I think you're still not understanding what Application.LoadLevel does. Or, maybe you don't understand what the various MonoBehaviour callbacks do (i.e., when they are called).

    Here's what the code above does when you run your game:
    1. The level begins, because you've hit the Run button or made a build where this is the first level in the build settings.
    2. An object containing the above component gets instantiated. (Its Awake method fires at this point, if it has one.)
    3. This object's Start method gets invoked next. The code above calls Application.LoadLevel("intro").
    4. Everything that just got created and set up gets torn down, and the "intro" level gets loaded instead.
    Is it clear how pointless that is? Moreover, if the script above is also on an object in the "intro" scene, then GoTo step 1 and do it all over again!

    And finally, of course, all that code in Update is utterly useless, since it never gets that far — you've told it to load a different scene (or reload the current one) as soon as the scene begins.

    Now, if we did make it as far as Update, you'd have more problems. You're starting a Coroutine on every frame of animation. That is a very bad thing. I recommend this procedure:

    1. Use the Find command in MonoDevelop to find every line containing "StartCoroutine".
    2. Delete any such line it finds.
    3. Rethink your life choices. ;)

    Just kidding — you only need to rethink your approach to the code.

    Here's a very general design principle: each component (script) should only have one job. Yes, it means that many of your scripts will be only a few lines long, but that's OK; in fact it's a good thing. It looks like the script above is trying to do two things: switch the level when a button is pressed, and also spawn waves of something. Those are two different jobs, and should be two different scripts.

    (And neither of them needs to have anything to do with coroutines!)