# Constructing Coroutines Dynamically?

Hello all, I have a system of lighting up little platforms upon players standing on them and unlighting them when they step off of them using coroutines and loops. The code works fine and this is solely a question on if it is possible to refine my method of doing so as my programming abilities seem to have reached their limit for this. The optimization I am trying to reach is not having to have 38 coroutines for the 38 respective blocks. I used to do this with a couple coroutines that would manage all the blocks but if a player were to quickly step on and off 2 or more blocks glitches would appear. The issue was that a coroutine that could handle all of them does not know WHICH block is being stepped off of so how does it know to unlight specifically that block? Looking at the code and how the loops work will show what I mean when you try to think of a system where one coroutine could do this:

I only am showing it with 2 blocks and one coroutine. Coroutine “F2” would simply be F1 copy and pasted. OneObj and TwoObj are the gameobjects of the blocks. This is how I check which block specifically is being stepped off of or onto. bools One and Two simply are there to make it so the coroutines only get called once ie. do not keep trying to light the same block. I am passing true or false into the coroutine for lighting or dimming respectively and passing the gameobject of the block. Once again, this only shows if two blocks were in the system and only shows one coroutine since “F2” would just be a copy of coroutine “F1”.

``````private void OnTriggerStay2D(Collider2D other)
{
if (other.gameObject.tag == "Glow")
{
if (OneObj == other.gameObject && !One)
{
One = true;
StopCoroutine("F1"); //Stops dimming if it is dimming. Would not call if already lighting.
StartCoroutine(F1(true, other.gameObject));
}
if (TwoObj == other.gameObject && !Two)
{
Two = true;
StopCoroutine("F2");
StartCoroutine(F2(true, other.gameObject));
}
}

}
private void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.tag == "Glow")
{
if (OneObj == other.gameObject && One)
{
One = false;
StopCoroutine("F1");
StartCoroutine(F1(false, other.gameObject));
}
if (TwoObj == other.gameObject && Two)
{
Two = false;
StopCoroutine("F2");
StartCoroutine(F2(false, other.gameObject));
}
}
}

public IEnumerator F1(bool Lighting, GameObject Obj)
{
if (Lighting)
{
yield return new WaitForSecondsRealtime(0.5f);
UnityEngine.Light FirstLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[0];
UnityEngine.Light SecondLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[1];
UnityEngine.Light ThirdLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[2];
float BlockLightI = FirstLight.intensity;
for (float i = 0f; i <= 3; i += 0.05f)
{
if (One) //Although not needed, if coroutine somehow does not stop this will stop the loop.
{
float NewIntensity = Mathf.Lerp(BlockLightI, 10f, i / 3f);
FirstLight.intensity = NewIntensity;
SecondLight.intensity = NewIntensity;
ThirdLight.intensity = NewIntensity;
yield return null;
}
else
{
yield break;
}
}
}
else //Not lighting so dimming. Is just what is above but backwards for the loop stuff.
{
UnityEngine.Light FirstLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[0];
UnityEngine.Light SecondLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[1];
UnityEngine.Light ThirdLight = Obj.GetComponentsInChildren<UnityEngine.Light>()[2];
float BlockLightI = FirstLight.intensity;
for (float i = 0f; i <= 3; i += 0.05f)
{
if (!One) //Once again a non-needed check. Just ensuring a block is either lighting or dimming. Not two different instances trying to do both at the same time and conflicting.
{
float NewIntensity = Mathf.Lerp(BlockLightI, 0f, i / 3f);
FirstLight.intensity = NewIntensity;
SecondLight.intensity = NewIntensity;
ThirdLight.intensity = NewIntensity;
yield return null;
if(FirstLight.intensity < 0.0001f)
{
FirstLight.intensity = 0f;
SecondLight.intensity = 0f;
ThirdLight.intensity = 0f;
yield break;
}
}
else
{
yield break;
}
}
}
}
``````

I would have to expand this code all the way to “F38”, 38 bools, and 38 gameobjects.

I am not even sure of the performance costs as only a couple of these coroutines would be active at once at most. I tried to make a system of one or two coroutines handling all 38 but run into an issue of the for loop inside not knowing when to stop dimming, for instance, if a player steps back on a block while it is dimming. Every solution I have found leads to 38 identifiers in some way. Even so, SOMETHING either needs to be in the for loop to stop the coroutine if a player steps back on (But remember 38 blocks), OR there needs to be 38 coroutines that I can just call to stop. You see both solutions in play here ("If (One) and If (!One) + StopCoroutine in the triggers).

My question, can I construct coroutines dynamically? The only way I see to get around using 38 is if I could change that “One” or “!One” bool based on whatever gameobject it is to Two or to Twenty etc and literally build a coroutine like a constructor almost. I could have maybe a massive nested loop in the coroutines to check this but it would also have to be in the loop anyway so that is not exactly optimal.
Thank you.

Sounds like you need exactly ONE coroutine and it needs to just accept a parameter for the block to manipulate.

Also rather than numbered variables you should just be using an array.

2 Likes

I have not used an array yet because I just wanted it simplified for this but I will. How would I pass through a variable that is at all useful to the for loop? I pass in one or two etc and it automatically becomes local to whatever its called in the coroutine parameters. I could change “One” etc globally and it would not matter to the coroutine as nothing I can put in the for loop parameters can be global. Unless you mean dynamically check it inside the loop?

38 coroutines for 38 blocks??? Madness.

This can just be distilled into a single component you put on each individual block. Meaning set up a prefab and duplicate it as much as needed.

1 Like

I fixed it by using just 38 gameobjects and one coroutine and checking if can loop inside the loop, would there not be a performance cost of 38 scripts regardless if theyre prefabbed?

Edit: Ended up using prefab version because I don’t have to assign a million gameobjects. Here is the code if anyone needs to do something similar and wants to use it:

``````using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LightBlocks : MonoBehaviour
{
bool CallOnce = false;
private void OnTriggerStay2D(Collider2D other)
{
if(!CallOnce)
{
CallOnce = true;
StopCoroutine("F1");
StartCoroutine(F1(true));
}
}
private void OnTriggerExit2D(Collider2D other)
{
if(CallOnce)
{
CallOnce = false;
StopCoroutine("F1");
StartCoroutine(F1(false));
}
}
public IEnumerator F1(bool WhichCase)
{
if (WhichCase)
{
yield return new WaitForSecondsRealtime(0.5f);
if (GetComponentInChildren<UnityEngine.Light>() != null)
{
UnityEngine.Light FirstLight = GetComponentsInChildren<UnityEngine.Light>()[0];
UnityEngine.Light SecondLight = GetComponentsInChildren<UnityEngine.Light>()[1];
UnityEngine.Light ThirdLight = GetComponentsInChildren<UnityEngine.Light>()[2];
float BlockLightI = FirstLight.intensity;
for (float i = 0f; i <= 3; i += 0.05f)
{
if (CallOnce)
{
float NewIntensity = Mathf.Lerp(BlockLightI, 10f, i / 3f);
FirstLight.intensity = NewIntensity;
SecondLight.intensity = NewIntensity;
ThirdLight.intensity = NewIntensity;
yield return null;
}
else
{
yield break;
}
}
}
}
else
{
if (GetComponentInChildren<UnityEngine.Light>() != null)
{
UnityEngine.Light FirstLight = GetComponentsInChildren<UnityEngine.Light>()[0];
UnityEngine.Light SecondLight = GetComponentsInChildren<UnityEngine.Light>()[1];
UnityEngine.Light ThirdLight = GetComponentsInChildren<UnityEngine.Light>()[2];
float BlockLightI = FirstLight.intensity;
for (float i = 0f; i <= 3; i += 0.05f)
{
if (!CallOnce)
{
float NewIntensity = Mathf.Lerp(BlockLightI, 0f, i / 3f);
FirstLight.intensity = NewIntensity;
SecondLight.intensity = NewIntensity;
ThirdLight.intensity = NewIntensity;
yield return null;
if (FirstLight.intensity < 0.0001f)
{
FirstLight.intensity = 0f;
SecondLight.intensity = 0f;
ThirdLight.intensity = 0f;
yield break;
}
}
else
{
yield break;
}
}
}
}
}
}
``````

Not particularly. We’re not talking numbers that would make a significant impact. I would have the component disabled by default (so no Update calls), and have it enable itself when the player collides with it/enters a trigger. Then it can just grow brighter until a certain point, and when the player gets off it, it dims until it’s off and disables itself.

1 Like