Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question While loop crashing

Discussion in 'Scripting' started by Minzent, Aug 29, 2023.

  1. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    Hello guys,

    I never really use while loops, so I'm very inexperienced with them. But I googled many times and searched for what a while loop needs to not crash, still, I can't figure out what the problem is.

    The condition the while loop needs should be met after some (or many) iterations of the loop. I don't understand why it's immediately crashing Unity when running.

    The loop is not in Update, it's being called one time in this callback when clicking a cookie in my game.

    Code (CSharp):
    1. private void InputHandler_OnCookieHit()
    2.     {
    3.         float screenWidth = Screen.width;
    4.  
    5.         float randomXScreen = UnityEngine.Random.Range(0f, screenWidth);
    6.         float borderDistance = Mathf.Abs(0f - randomXScreen);
    7.  
    8.         if (borderDistance > minBorderDistance)
    9.         {
    10.             Debug.Log("Border distance higher than the minimum!");
    11.             while (borderDistance > minBorderDistance)
    12.             {
    13.                 Debug.Log("Border distance STILL higher!");
    14.                 randomXScreen = UnityEngine.Random.Range(0f, screenWidth);
    15.                 borderDistance = Mathf.Abs(0f - randomXScreen);
    16.  
    17.                 if (borderDistance < minBorderDistance)
    18.                 {
    19.                     Debug.Log("Border distance now smaller!");
    20.                     break;
    21.                 }
    22.             }
    23.         }
    24.  
    25.     }
    I tried it without a statement within the loop too.

    Thanks for any help, this is really breaking my head now :/
     
  2. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    711
    any loop that just goes round and round and isnt playing nice (eg letting anything else get a word in) tends to crash unity..
     
  3. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,140
    As mentioned, if your if statement never executes, while will run forever. So, you'll need to double check that your if statement actually can be true. However, not sure the purpose of the while loop. Remember that unless you're in a coroutine with a yield inside the loop, once in the loop, it will execute completely or stay in the loop without doing anything else still it finally exits or freezes up because it never does exit.
     
  4. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    This makes no sense:
    Code (CSharp):
    1. float randomXScreen = UnityEngine.Random.Range(0f, screenWidth);
    2. float borderDistance = Mathf.Abs(0f - randomXScreen);
    As you're getting a positive number from Random, then you make it negative within a method that makes a negative a positive. So not sure where that idea came from, but it's just wasted processes.

    Also debug logs are very performance hitting, so if you have a run-away loop, trying to print every tick would surely crash Unity, guaranteed.

    But reading over your code, several times, I still can't figure out what you're trying to accomplish. Can you give more insight to why the Random needs to be over or under the minimum?
     
    CodeRonnie and Bunny83 like this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Unity will lock up 100% of the time EVERY millisecond your scripting code is running.

    Nothing will render, no input will be processed, no Debug.Log() will come out, no GameObjects or transforms will appear to update.

    Absolutely NOTHING will happen... until your code either:

    - returns from whatever function it is running

    - yields from whatever coroutine it is running

    As long as your code is looping, Unity isn't going to do even a single frame of change. Nothing.

    No exceptions.

    "Yield early, yield often, yield like your game depends on it... it does!" - Kurt Dekker

    If you think your loop SHOULD be exiting because of the values in that if() clause, then your values are not what you think they are and it is...

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
  6. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19

    The subtraction result has to be positive. Without absolute, the subtraction result would be negative.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Don't tell us!! We're not the ones preventing you from leaving the while() loop.

    Put an unconditional
    break;
    at the end of the while loop and start printing values.

    As I noted above, one of those values is NOT what you think it is.
     
    Bunny83 likes this.
  8. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    I tried replying to the question I was asked. And by this time your answer wasn't even here yet, so I still have to read it. But thank you.
     
  9. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    The subtraction result doesn't need to be in existence... That's my point.

    Random.Range(minimum number, maximum number). So if maximum number is screen width, it is a positive. Subtracting 0 by it, then making that negative number you just made for no reason, a positive number again, makes no sense.

    It's equivalent to saying:
    Code (CSharp):
    1. myGameObject = gameObject1;
    2. myGameObject = null; // wasted process
    3. myGameObject = gameObject1; // wasted process
    4. myGameObject.DoSomething();
     
    Bunny83 likes this.
  10. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    Thanks bro, apparently it was indeed the fault of the Logs. I removed them completely from within the while loop and it works perfectly fine now, just as I intended, so everything else was apparently correct from my side. Maybe the naming was a bit off or because of the lack of commenting you couldn't understand what I was trying to do. But anyway, thanks for this suggestion, it fixed my problem!
     
  11. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    oof...

    Either way, you do you, it's working and that's all that matters.
     
  12. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    Some people just haven't been in the industry for 30 years and will sometimes make the silliest kind of mistakes, that's what you have to deal with too when helping newbies in these kinds of forums :)

    Still thanks for your help, wish you all the best :)
     
    Kurt-Dekker likes this.
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I have been in the industry over 40 years and I still make silly mistakes... every single day.

    I'm not exaggerating. We humans are TERRIBLE software engineers! Terrible!

    That's why it is far more important to be able to print the values out that you are computing because the answer is almost always in the data.
     
  14. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    I'm not referring to that, of course I understand that your not grasping the concept. I approach every post as the person has no clue, as it's easy because sometimes I also have no clue! lol..

    My point was more referring to the fact you didn't read what was written:
    So the frustration comes from not just reading things.. I too have this problem, sometimes taking days on understanding my own method I wrote.. and then complaining "I need to ask the guy who wrote this, to what it means".. Talk a bout run-away loops. :D

    But, all good, we all have our pet-peeves
     
  15. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    I don't think you even understood what @wideeyenow_unity said. Look, this code will print true:

    Code (CSharp):
    1.     float randomXScreen = UnityEngine.Random.Range(0f, screenWidth);
    2.     float borderDistance = Mathf.Abs(0f - randomXScreen);
    3.     if (randomXScreen == borderDistance)
    4.     {
    5.         Debug.Log("true");
    6.     }
    7.  
    So your subtraction and your Mathf.Abs are completely redundant.

    Just to state some facts about your code:
    • randomXScreen is either 0 or a positive number
    • 0-randomXScreen
      is the same as
      -randomXScreen
      , so it makes the number negative
    • Mathf.Abs when feeded a negative number
      x
      will return
      -x
    • Therefore your code does perform those steps
      -(-randomXScreen)
      which is completely pointless.
    What's even the point of the loop in the first place? Your
    minBorderDistance
    actually acts like a maximum and all it does is ensuring the borderDistance is some value smaller or equal to "minBorderDistance". So if that's your actual goal, why don't you roll a number between 0 and minBorderDistance ? This already ensures the number is between 0 and minBorderDistance. The endresult will ALWAYS be in that range anyways...
     
    wideeyenow_unity likes this.
  16. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    I think you misworded this?

    As any number, positive or negative, fed into Mathf.Abs gives the positive value returned.
     
  17. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    Ohh, you just mean it inverts it, if it is negative... never mind me, I'm just off into space, lol
     
    Bunny83 likes this.
  18. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Right. Mathf.Abs is literally just
    Code (CSharp):
    1. public static float Abs(float val)
    2. {
    3.     return (val < 0)? -val : val;
    4. }
    5.  
    Technically Unity uses Math.Abs which is implemented externally and has a special implementation to ensure proper handling of NaN values as you can read in the comments. Though the actual function is still just that.
     
  19. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    The code you posted achieves essentially the same output as this.
    Code (CSharp):
    1.  
    2. private void InputHandler_OnCookieHit()
    3. {
    4.     float randomXScreen, borderDistance = UnityEngine.Random.Range(0f, minBorderDistance);
    5. }
    6.  
    Except that your version can get stuck in a loop for a random amount of time. When you do Unity's Debug.Log() calls in that loop, the memory allocations that Unity generates is exceeding the amount of RAM you have on your system because you are stuck in that loop so long within a single frame and nothing is cleaned up. That's why you're crashing. If you take the calls out, you don't crash, but you're still just spinning in a loop unnecessarily for a random length of time, probably way too long to do anything in a video game.

    Bunny83 is asking, even with the code condensed the way I've done it, why are you calling essentially one line of code to assign two local variables the same value and do nothing with that value?
     
    Bunny83 likes this.
  20. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    I remember that particular method being mentioned in this video(TimeStamp: 48:10):

    And that it may be best to just make your own check.
     
  21. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    I actually was a bit drunk here and inverted it for some reason just for testing. The loop should check for < instead of >
    Maybe this clears up some confusion
     
  22. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Not really :) If you want a min border distance, why don't you pass your "minBorderDistance" as the lower limit to Random.Range? It literally has a min and max parameter...
     
    dlorre and bugfinders like this.
  23. Minzent

    Minzent

    Joined:
    Mar 9, 2019
    Posts:
    19
    I didnt do it this way because i didnt think of it. Should be kinda obvious. But you are right, this should work too.