Search Unity

Bug While loop crashing Unity

Discussion in 'Scripting' started by Myst1cS04p, May 10, 2023.

  1. Myst1cS04p

    Myst1cS04p

    Joined:
    Oct 10, 2022
    Posts:
    17
    I'm making a boss and I have some code that's supposed to make it spin for 5 seconds and then stop spinning. Only problem is the fact that the loop I'm using for this just crashes unity I've tried browsing for an answer, I found a thread that says unity will crash if the loop never ends, so I checked and realized my loop was indeed never going to reach the end because the statement that modified the variable to stop the loop was outside the loop so i fixed that but it still crashes.
    Code:
    Code (CSharp):
    1. public class Spin : StateMachineBehaviour
    2. {
    3.     private float damage;
    4.     [SerializeField] private float spinDura = 5;
    5.     private Breserker breserker;
    6.     private Axe_Spin axeSpinHitbox;
    7.     // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    8.     override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    9.     {
    10.  
    11.         breserker = animator.GetComponent<Breserker>();
    12.         axeSpinHitbox = breserker.transform.Find(breserker.axeSpinHitboxName).GetComponent<Axe_Spin>();
    13.         axeSpinHitbox.Spin(spinDura);
    14.     }
    15.  
    16.     // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    17.     override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    18.     {
    19.     }
    20.     // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    21.     override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    22.     {
    23.  
    24.     }
    Axe spin hitbox.Spin()
    Code (CSharp):
    1.     public void Spin(float spinDura)
    2.     {
    3.         spinning = true;
    4.         StartCoroutine(SpinTimer(spinDura));
    5.         while (spinning)
    6.         {
    7.             breserker.transform.Rotate(new(0, spinSpeed, 0));
    8.         }
    9.     }
    10.     public IEnumerator SpinTimer(float spinDura)
    11.     {
    12.         yield return new WaitForSeconds(spinDura);
    13.         spinning = false;
    14.     }
     
  2. Reaktion

    Reaktion

    Joined:
    Nov 8, 2019
    Posts:
    53
    Hi,

    Here, you have an infinite loop that you're trying to stop later in the application. The problem is that Unity is executing your while loop during the frame, and it has no end on this current frame, so there is no way for Unity to render the frame after the code execution, because the while loop never ends.

    If you want code to be executed at every frame on MonoBehaviour's objects in Unity, you have to use the Update function.

    A better way to do this for you is to call inside the Update function a function called UpdateSpin, where you check you're spinning boolean value, if you're spinning the berserker or not.
    In order to wait for seconds to stop spinning, you can create a float variable, that you will increment (or decrement) by Time.deltaTime. After that, when your float reaches the limit, you can stop spinning.
     
    Myst1cS04p likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
    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
     
    Myst1cS04p and Bunny83 like this.
  4. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,187
    Your code had an infinite loop for the reasons mentioned above.
    Code (csharp):
    1. public IEnumerator Spin(float spinDura)
    2. {
    3.     float elapsedTime = 0f;
    4.     while (elapsedTime < spinDura)
    5.     {
    6.         breserker.transform.Rotate(0f, spinSpeed * Time.deltaTime, 0f);
    7.         elapsedTime += Time.deltaTime;
    8.         yield return null;
    9.     }
    10. }
    You can then start the coroutine from the state machine behaviour.
    Code (csharp):
    1. axeSpinHitbox.StartCoroutine(axeSpinHitbox.Spin(spinDura));
     
    Last edited: May 10, 2023
    Myst1cS04p and Bunny83 like this.