Running multiple loops at the same time using a coroutine?

I have a problem where calling a method that supposed to loop at the same time is being called one at a time.

I’m trying to implement a map trigger where IF a player touched the trigger, it will change the opacity of the target Game Objects.

The code is here: (ps. Please tell me if this is the correct way to do this)

public class OpacityChangeScr : MonoBehaviour {

	public GameObject[] targets;
	public float value;
	public float time;
	
	// Update is called once per frame
	void OnTriggerEnter2D (Collider2D collider) {
		if (collider.gameObject.layer == LayerMask.NameToLayer("player")){
			StartCoroutine("startChange");
		}
	}
	
	IEnumerator startChange(){	
		foreach (GameObject obj in targets){
			yield return StartCoroutine( changeOpacity(obj) );
		}
	}
	
	IEnumerator changeOpacity(GameObject obj){
		float i = 0;
		float rate = 1.0f / time;
		Color temp = obj.renderer.material.color;
		
		while (i < 1.0f){
			i += Time.deltaTime * rate;
			temp.a = Mathf.Lerp(obj.renderer.material.color.a, value, i);
			obj.renderer.material.color = temp;
			
			//Continue frame update
			yield return new WaitForEndOfFrame();
		}
	}
}

When the player touched the trigger, it will call the startChange method then the method will call the changeOpacity method while passing the game object(s) in the array.

It works, but the problem is – it loops one at a time. So when I test it in game, it changes the opacity one object at a time. How will I make it so that all target game objects changes opacity at the same time?

Hi.
as far as i know the " StartCoroutine" creates an individual instance of a coroutine
so you can just change
this :

 IEnumerator startChange(){    
         foreach (GameObject obj in targets){
             yield return StartCoroutine( changeOpacity(obj) );
         }
     }

to this :

 IEnumerator startChange(){    
         foreach (GameObject obj in targets){
             StartCoroutine( changeOpacity(obj) );
         }
         yield return null;
     }

with “yield return StartCoroutine” you just say that you want to wait till the called coroutine finish then call the next one.