Search Unity

Stop multiple Coroutine

Discussion in 'Scripting' started by Zavalichi, May 10, 2019.

  1. Zavalichi

    Zavalichi

    Joined:
    Oct 13, 2018
    Posts:
    162
    Hi guys,

    I have a traffic manager with three traffic lights. Every traffic lights has three colors(red, yellow and green).
    Every traffic lights has an index (i), so i = 0, 1, 2.
    My update method works fine, but if for one of the trafficlights I want to change the color and start with that color it works weird.

    For example: Tfl1: green, TfL2: green, Tfl3: red
    I want to change: TfL1 to yellow, but when I do this, my traffic lights TfL1 (index i=0) goes a weird comportament .

    Code (CSharp):
    1.    private void startTrafficLights(Transform trafficLights, int i)
    2.     {
    3.         getLights(trafficLights, i);
    4.  
    5.         Red[i].enabled = false;
    6.         Yellow[i].enabled = false;
    7.         Green[i].enabled = false;
    8.  
    9.         if (gameObject.transform.childCount == 2)   // Sync two traffic lights
    10.             _timer[i] = GreenLight(i);
    11.         else
    12.         {
    13.             if ((_dim >= 2) && (_dim <= 4))   // Sync two pairs of traffic lights
    14.             {
    15.                 if ((trafficLights.name == "TfL1") || (trafficLights.name == "TfL2"))
    16.                     _timer[i] = GreenLight(i);
    17.                 else
    18.                     _timer[i] = RedLight(i);
    19.             }
    20.         }
    21.         if (_timer[i] != null)
    22.             StartCoroutine(_timer[i]);
    23.     }
    Code (CSharp):
    1.   void Update()
    2.     {
    3.         if (_readyForUpdate)
    4.             for (int i = 0; i < _dim; ++i)
    5.                 updateTrafficLights(gameObject.transform.GetChild(i), i);
    6.     }
    Code (CSharp):
    1. private void updateTrafficLights(Transform trafficLights, int i)
    2.     {
    3.         if (_change == 1)
    4.         {
    5.             if (i == 0)
    6.                 Debug.Log("TFL1 face update de culoare");
    7.  
    8.             if (_isGreen == true)
    9.             {
    10.                 _isGreen = false;
    11.                 _change = 0;
    12.                 _timer = GreenLight(i);
    13.             }
    14.             if (_isYellow == true)
    15.             {
    16.                 _isYellow = false;
    17.                 _change = 0;
    18.                 _timer = YellowLight(i);
    19.             }
    20.             if (_isRed == true)
    21.             {
    22.                 _isRed = false;
    23.                 _change = 0;
    24.                 _timer = RedLight(i);
    25.             }
    26.             if (_timer != null)
    27.                 StartCoroutine(_timer);
    28.         }
    29.     }


    Code (CSharp):
    1.  
    2.     /// <summary>
    3.     /// Toggle red light
    4.     /// </summary>
    5.     /// <param name="i"></param>
    6.     /// <returns></returns>
    7.     IEnumerator RedLight(int i)
    8.     {
    9.         RemainingTime[i] = RedTime[i];
    10.         Red[i].enabled = true;
    11.         _readyForUpdate = false;
    12.  
    13.         while (RemainingTime[i] > 0)
    14.         {
    15.             yield return new WaitForSeconds(1);
    16.             RemainingTime[i]--;
    17.         }
    18.  
    19.         Red[i].enabled = false;
    20.         _change[i] = 1;
    21.         _isGreen[i] = true;
    22.         _readyForUpdate = true;
    23.     }
    24.  
    25.     /// <summary>
    26.     /// Toggle yellow light
    27.     /// </summary>
    28.     /// <param name="i"></param>
    29.     /// <returns></returns>
    30.     IEnumerator YellowLight(int i)
    31.     {
    32.         RemainingTime[i] = YellowTime[i];
    33.         Yellow[i].enabled = true;
    34.         _readyForUpdate = false;
    35.  
    36.         while (RemainingTime[i] > 0)
    37.         {
    38.             yield return new WaitForSeconds(1);
    39.             RemainingTime[i]--;
    40.         }
    41.  
    42.         Yellow[i].enabled = false;
    43.         _change[i] = 1;
    44.         _isRed[i] = true;
    45.         _readyForUpdate = true;
    46.     }
    47.  
    48.     /// <summary>
    49.     /// Toggle green light
    50.     /// </summary>
    51.     /// <param name="i"></param>
    52.     /// <returns></returns>
    53.     IEnumerator GreenLight(int i)
    54.     {
    55.         RemainingTime[i] = GreenTime[i];
    56.         Green[i].enabled = true;
    57.         _readyForUpdate = false;
    58.  
    59.         while (RemainingTime[i] > 0)
    60.         {
    61.             yield return new WaitForSeconds(1);
    62.             RemainingTime[i]--;
    63.         }
    64.  
    65.         Green[i].enabled = false;
    66.         _change[i] = 1;
    67.         _isYellow[i] = true;
    68.         _readyForUpdate = true;
    69.     }
    70.  
    71.     public void ChangeRedLight(int i)
    72.     {
    73.         _timer[i] = YellowLight(i);
    74.         StopCoroutine(_timer[i]);
    75.  
    76.         _timer[i] = GreenLight(i);
    77.         StopCoroutine(_timer[i]);
    78.  
    79.         _readyForUpdate = false;
    80.         Yellow[i].enabled = false;
    81.         Green[i].enabled = false;
    82.  
    83.         _timer[i] = RedLight(i);
    84.         StartCoroutine(_timer[i]);
    85.     }
    86.  
    87.     public void ChangeYellowLight(int i)
    88.     {
    89.        _timer[i] = RedLight(i);
    90.         StopCoroutine(_timer[i]);
    91.         _timer[i] = GreenLight(i);
    92.         StopCoroutine(_timer[i]);
    93.         _readyForUpdate = false;
    94.         Red[i].enabled = false;
    95.         Green[i].enabled = false;
    96.  
    97.         _timer[i] = YellowLight(i);
    98.         StartCoroutine(_timer[i]);
    99.     }
    100.  
    101.     public void ChangeGreenLight(int i)
    102.     {
    103.         _timer[i] = RedLight(i);
    104.         StopCoroutine(_timer[i]);
    105.         _timer[i] = YellowLight(i);
    106.         StopCoroutine(_timer[i]);
    107.  
    108.         _readyForUpdate = false;
    109.         Red[i].enabled = false;
    110.         Yellow[i].enabled = false;
    111.  
    112.         _timer[i] = GreenLight(i);
    113.         StartCoroutine(_timer[i]);
    114.     }
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    It would be significantly easier if you used an enum to track the state of the traffic light, as it can only be in one state at any given time.

    Code (csharp):
    1.  
    2. enum TrafficLightState { Red, Yellow, Green }
    3.  
    4. TrafficLightState currentState = TrafficLightState.Red;
    5.  
    That would simplify a lot of logic you have and make it easier to debug in the future. Having said that, your issue is mainly with this kind of code:

    Code (csharp):
    1.  
    2. // some if statements and other logic until you eventually do:
    3. _timer[i] = GreenLight(i); // or YellowLight(i) or RedLight(i)
    4.  
    5. // then later you do:
    6. if (_timer[i] != null)
    7.             StartCoroutine(_timer[i]);
    8.  
    The first bit of code runs the function already and then StartCoroutine runs it again. That's why your state is getting messed up.
     
  3. Zavalichi

    Zavalichi

    Joined:
    Oct 13, 2018
    Posts:
    162
    I tried:
    Code (CSharp):
    1. _timer[i] = RedLight(i);
    2.         StopCoroutine(_timer[i]);
    3.  
    4. _timer[i] = YellowLight(i);
    5.         StopCoroutine(_timer[i]);
    6.  
    7. _timer[i] = GreenLight(i);
    8. StopCoroutine(_timer[i]);
    9.  
    10. _readyForUpdate = false;
    11.         Yellow[i].enabled = false;
    12.         Green[i].enabled = false;
    13.  
    14.         _timer[i] = RedLight(i);
    15.         StartCoroutine(_timer[i]);
    But still doesn't work
    If I use this:

    Code (CSharp):
    1.     public void ChangeColorLight(bool[] red, bool[] yellow, bool[] green)
    2.     {
    3.         StopAllCoroutines();
    4.         _readyForUpdate = false;
    5.         for(int i = 0; i < Dim; ++i )
    6.         {
    7.             Debug.Log(red[i] + " " + yellow[i] + "  " + green[i]);
    8.             Red[i].enabled = false;
    9.             Yellow[i].enabled = false;
    10.             Green[i].enabled = false;
    11.  
    12.             if (red[i] == true)
    13.                 _timer[i] = RedLight(i);
    14.             if (yellow[i] == true)
    15.                 _timer[i] = YellowLight(i);
    16.             if (green[i] == true)
    17.                 _timer[i] = GreenLight(i);
    18.         }
    19.         StartCoroutine(_timer[0]);
    20.         StartCoroutine(_timer[1]);
    21.         StartCoroutine(_timer[2]);
    22.  
    23.     }
    It works, but the problem is when i change a traffic lights status, all trafic lights from that intersection will reset the counter
     
    Last edited: May 10, 2019
  4. xenonmiii

    xenonmiii

    Joined:
    Aug 2, 2010
    Posts:
    147
    @Zavalichi
    Hi, I thought I had a quick go at making a simple traffic light object.
    Here are my assumptions.
    The traffic light has 3 states, green, yellow, red. And from the red it goes back to green.
    Each light has individual timing.

    Here's the code:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. class TrafficLight : MonoBehaviour
    4. {
    5.     //We will use the index to these variables according to the state
    6.     //Make sure to set these as they are done in TrafficLightState, i.e. 0 = Green, 1 = Yellow, 2 = Red;
    7.     public GameObject[] sprites;
    8.     public float[] timings;
    9.  
    10.     public enum TrafficLightState
    11.     {
    12.         Green,
    13.         Yellow,
    14.         Red,
    15.         NUM_STATES
    16.     }
    17.  
    18.     TrafficLightState state;
    19.     public TrafficLightState startingState;
    20.     float timeLeftToChange;
    21.  
    22.     void Start()
    23.     {
    24.         SetNewState(startingState);
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         timeLeftToChange -= Time.deltaTime;
    30.         if (timeLeftToChange <= 0)
    31.         {
    32.             var nextState = ((int)state + 1) % (int)TrafficLightState.NUM_STATES;
    33.             SetNewState((TrafficLightState)nextState);
    34.         }
    35.     }
    36.  
    37.     void SetNewState(TrafficLightState newState)
    38.     {
    39.         state = newState;
    40.         foreach (var s in sprites)
    41.         {
    42.             s.SetActive(false);
    43.         }
    44.         var stateIndex = (int)state;
    45.         sprites[stateIndex].SetActive(true);
    46.         timeLeftToChange = timings[stateIndex];
    47.     }
    48.  
    49. }
    Let me know if you have any questions on the code, or if I missed some requirement.
    P.S. I didn't test the code :)