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): private void startTrafficLights(Transform trafficLights, int i) { getLights(trafficLights, i); Red[i].enabled = false; Yellow[i].enabled = false; Green[i].enabled = false; if (gameObject.transform.childCount == 2) // Sync two traffic lights _timer[i] = GreenLight(i); else { if ((_dim >= 2) && (_dim <= 4)) // Sync two pairs of traffic lights { if ((trafficLights.name == "TfL1") || (trafficLights.name == "TfL2")) _timer[i] = GreenLight(i); else _timer[i] = RedLight(i); } } if (_timer[i] != null) StartCoroutine(_timer[i]); } Code (CSharp): void Update() { if (_readyForUpdate) for (int i = 0; i < _dim; ++i) updateTrafficLights(gameObject.transform.GetChild(i), i); } Code (CSharp): private void updateTrafficLights(Transform trafficLights, int i) { if (_change == 1) { if (i == 0) Debug.Log("TFL1 face update de culoare"); if (_isGreen == true) { _isGreen = false; _change = 0; _timer = GreenLight(i); } if (_isYellow == true) { _isYellow = false; _change = 0; _timer = YellowLight(i); } if (_isRed == true) { _isRed = false; _change = 0; _timer = RedLight(i); } if (_timer != null) StartCoroutine(_timer); } } Code (CSharp): /// <summary> /// Toggle red light /// </summary> /// <param name="i"></param> /// <returns></returns> IEnumerator RedLight(int i) { RemainingTime[i] = RedTime[i]; Red[i].enabled = true; _readyForUpdate = false; while (RemainingTime[i] > 0) { yield return new WaitForSeconds(1); RemainingTime[i]--; } Red[i].enabled = false; _change[i] = 1; _isGreen[i] = true; _readyForUpdate = true; } /// <summary> /// Toggle yellow light /// </summary> /// <param name="i"></param> /// <returns></returns> IEnumerator YellowLight(int i) { RemainingTime[i] = YellowTime[i]; Yellow[i].enabled = true; _readyForUpdate = false; while (RemainingTime[i] > 0) { yield return new WaitForSeconds(1); RemainingTime[i]--; } Yellow[i].enabled = false; _change[i] = 1; _isRed[i] = true; _readyForUpdate = true; } /// <summary> /// Toggle green light /// </summary> /// <param name="i"></param> /// <returns></returns> IEnumerator GreenLight(int i) { RemainingTime[i] = GreenTime[i]; Green[i].enabled = true; _readyForUpdate = false; while (RemainingTime[i] > 0) { yield return new WaitForSeconds(1); RemainingTime[i]--; } Green[i].enabled = false; _change[i] = 1; _isYellow[i] = true; _readyForUpdate = true; } public void ChangeRedLight(int i) { _timer[i] = YellowLight(i); StopCoroutine(_timer[i]); _timer[i] = GreenLight(i); StopCoroutine(_timer[i]); _readyForUpdate = false; Yellow[i].enabled = false; Green[i].enabled = false; _timer[i] = RedLight(i); StartCoroutine(_timer[i]); } public void ChangeYellowLight(int i) { _timer[i] = RedLight(i); StopCoroutine(_timer[i]); _timer[i] = GreenLight(i); StopCoroutine(_timer[i]); _readyForUpdate = false; Red[i].enabled = false; Green[i].enabled = false; _timer[i] = YellowLight(i); StartCoroutine(_timer[i]); } public void ChangeGreenLight(int i) { _timer[i] = RedLight(i); StopCoroutine(_timer[i]); _timer[i] = YellowLight(i); StopCoroutine(_timer[i]); _readyForUpdate = false; Red[i].enabled = false; Yellow[i].enabled = false; _timer[i] = GreenLight(i); StartCoroutine(_timer[i]); }
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): enum TrafficLightState { Red, Yellow, Green } TrafficLightState currentState = TrafficLightState.Red; 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): // some if statements and other logic until you eventually do: _timer[i] = GreenLight(i); // or YellowLight(i) or RedLight(i) // then later you do: if (_timer[i] != null) StartCoroutine(_timer[i]); The first bit of code runs the function already and then StartCoroutine runs it again. That's why your state is getting messed up.
I tried: Code (CSharp): _timer[i] = RedLight(i); StopCoroutine(_timer[i]); _timer[i] = YellowLight(i); StopCoroutine(_timer[i]); _timer[i] = GreenLight(i); StopCoroutine(_timer[i]); _readyForUpdate = false; Yellow[i].enabled = false; Green[i].enabled = false; _timer[i] = RedLight(i); StartCoroutine(_timer[i]); But still doesn't work If I use this: Code (CSharp): public void ChangeColorLight(bool[] red, bool[] yellow, bool[] green) { StopAllCoroutines(); _readyForUpdate = false; for(int i = 0; i < Dim; ++i ) { Debug.Log(red[i] + " " + yellow[i] + " " + green[i]); Red[i].enabled = false; Yellow[i].enabled = false; Green[i].enabled = false; if (red[i] == true) _timer[i] = RedLight(i); if (yellow[i] == true) _timer[i] = YellowLight(i); if (green[i] == true) _timer[i] = GreenLight(i); } StartCoroutine(_timer[0]); StartCoroutine(_timer[1]); StartCoroutine(_timer[2]); } It works, but the problem is when i change a traffic lights status, all trafic lights from that intersection will reset the counter
@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): using UnityEngine; class TrafficLight : MonoBehaviour { //We will use the index to these variables according to the state //Make sure to set these as they are done in TrafficLightState, i.e. 0 = Green, 1 = Yellow, 2 = Red; public GameObject[] sprites; public float[] timings; public enum TrafficLightState { Green, Yellow, Red, NUM_STATES } TrafficLightState state; public TrafficLightState startingState; float timeLeftToChange; void Start() { SetNewState(startingState); } void Update() { timeLeftToChange -= Time.deltaTime; if (timeLeftToChange <= 0) { var nextState = ((int)state + 1) % (int)TrafficLightState.NUM_STATES; SetNewState((TrafficLightState)nextState); } } void SetNewState(TrafficLightState newState) { state = newState; foreach (var s in sprites) { s.SetActive(false); } var stateIndex = (int)state; sprites[stateIndex].SetActive(true); timeLeftToChange = timings[stateIndex]; } } 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