Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Bug Boss State Machine Error

Discussion in 'Scripting' started by AnUnifiedDev, Apr 27, 2024.

  1. AnUnifiedDev

    AnUnifiedDev

    Joined:
    Jul 18, 2019
    Posts:
    4
    Got a simple state machine going for a boss battle. In one of the states, I want to have the boss decide a random number of bullets to shoot, shoot each bullet with some time in between, and then go to the next state if it met its number of bullets.

    In reality, my game has the boss spit out hundreds of bullets constantly at the same time and never transitions out of the state. And I have no idea why this is the case.

    I attached the important parts related to this problem below.

    Code (CSharp):
    1. public enum StateController
    2. {
    3.     Idle,
    4.     Run,
    5.     Jump,
    6.     Shoot,
    7.     COUNT
    8. }
    9. .........
    10. void Update()
    11.     {
    12.      
    13.             switch (currentState)
    14.             {
    15.                 case StateController.Idle:
    16.                     BossIdle();
    17.                     break;
    18.                 //case StateController.Run:
    19.                 //    BossRun();
    20.                 //    break;
    21.                 case StateController.Jump:
    22.                     StartCoroutine(BossJump());
    23.                     break;
    24.                 case StateController.Shoot:
    25.                     //BossShoot();
    26.                     StartCoroutine(BossShoot());
    27.                     break;
    28.             }
    29.         }
    30.     }
    31.  
    32. ......
    33.  
    34.  
    35. IEnumerator BossShoot()
    36.     {
    37.         int numShots = 2;
    38.         for (int x = numShots; !(x > numShots); x--)
    39.         {
    40.             //GameObject go = Instantiate(bullet, bulletPos.position, Quaternion.identity);
    41.             //Vector3 direction = new Vector3(transform.localScale.x, 0);
    42.  
    43.             Instantiate(bullet, bulletPos.position, Quaternion.identity);
    44.             Debug.Log("Boss is shooting");
    45.  
    46.             yield return new WaitForSecondsRealtime(2);
    47.             if (x == 0)
    48.             {
    49.                 ChangeState(StateController.Idle);
    50.             }
    51.         }
    52.     }
    53.  
    54. public void ChangeState (StateController newState)
    55.     {
    56.         if (currentState == newState)
    57.         {
    58.             return;
    59.         }
    60.  
    61.         newState = (StateController)Random.Range(0, (int)StateController.COUNT);
    62.         currentState = newState;
    63.         timeInState = 0f;
    64.     }
     
    Last edited: Apr 27, 2024
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,434
    Sounds like a bug!! That means it is time to start debugging!

    By debugging you can find out exactly what your program is doing so you can fix it.

    https://docs.unity3d.com/Manual/ManagedCodeDebugging.html

    Use the above techniques to get the information you need in order to reason about what the problem is.

    You can also use Debug.Log() to find out if any of your code is even running. Don't assume it is.

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

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    1,128
    When you start a coroutine the Update function still continues to update along side the coroutine. So your Update function is repeatedly starting the BossShoot() coroutine every frame resulting in hundreds of them running along side each other.

    To fix it you'll need to make your coroutines set a common bool when they've finished, which your Update function can then check before deciding which coroutine to start next.

    You could even consider scrapping your Update function and having all of your states be coroutines which start other coroutines/states.

    Personally I use delegates for a state machine as it's a little more efficient compared to case/switch. But I can see that you're attracted to coroutines for their yield and WaitForSeconds().
     
  4. AnUnifiedDev

    AnUnifiedDev

    Joined:
    Jul 18, 2019
    Posts:
    4
    And yep, that fixed it. I never knew Coroutines worked that way, which is good to keep in mind. Thank you kindly!