StartCoroutine in a separate class

Hi, I’m experimenting with StartCoroutine and i’ve ran into an issue. I have a SphereController class which contains the following:

            Sphere referenceToSphereOne = CurrentlySelected[0].GetComponent<Sphere> ();
			Sphere referenceToSphereTwo = CurrentlySelected[1].GetComponent<Sphere> ();
			
			// Set targets to the opposite transforms
			referenceToSphereOne.SetSphereTarget (CurrentlySelected[1].transform.position);
			referenceToSphereTwo.SetSphereTarget (CurrentlySelected[0].transform.position);
			
			StartCoroutine ( referenceToSphereOne.IETESTUpdatePosition() );

So basically it access the script type Sphere of two game objects and tells them to swap their positions. I then have a Sphere class which contains the following:

public IEnumerator IETESTUpdatePosition()
{
	Debug.Log("Entering ie test");
	transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * 4.0f);
	
	yield return AreAtSamePosition( transform.position, targetPosition );
	
}

public bool AreAtSamePosition (Vector3 vectorOne, Vector3 vectorTwo)
{
	// Note that we ignore the Z axis	
	
	if (Mathf.Approximately (vectorOne.x, vectorTwo.x) && Mathf.Approximately (vectorOne.y, vectorTwo.y)) {
		return true;
	} else {
		return false;
	}
	
}

So what I’m trying to accomplish is the SphereController to tell the Sphere to swap positions and only return when they have reached their target positions.

However, I’m running into issues as soon as I trying to call the coroutine in SphereController:

StartCoroutine ( referenceToSphereOne.IETESTUpdatePosition() );

Although I have a reference to the script, the compiler is complaining that an object reference is required to access non static member etc etc

As I’m inexperienced with coroutines I wondered if anyone could help with this error and also whether the remaining code will achieve what I’m after!

Many thanks

Well, that’s not how coroutines works. You can see coroutines are “normal” functions but they can be interrupted at certain points. Those points are your “yield return” statements. The yield return statement will leave the function at this point and just returns a value back to the controlling system. Unity is the controlling system in our case and it will decide what to do next on the basis of the value you returned. In your case you call your function AreAtSamePosition which returns a boolean. If you yield return a boolean Unity will just wait a single frame and continue after your yield statement. Your function ends there so nothing special happens in this case.

I guess you want to move it towards the target until it reaches the end. You have to use a loop like this:

public IEnumerator IETESTUpdatePosition()
{
    Debug.Log("Entering ie test");
    while (!AreAtSamePosition( transform.position, targetPosition ))
    {
        transform.position = Vector3.Lerp (transform.position, targetPosition, Time.deltaTime * 4.0f);
        yield return false; // this will wait for the next frame.
    }
    Debug.Log("Reached target");
}

You can’t use “yield return” with AreAtSamePosition, or rather you can, but it won’t accomplish anything. In order to properly yield on a function, it needs to be a coroutine, and that coroutine needs to take place over a period of time, not return immediately (which means you can’t make a coroutine return true or false, since all coroutines must return IEnumerator). Also, you’re not using Lerp correctly. It’s just a math function that returns a value immediately, it doesn’t “do stuff over time” or anything. See the Translation function here for an example of a coroutine that uses Lerp repeatedly to move an object from one position to another.

Bunny83 - thanks so much for taking the time to explain this. Theoretically, I’m starting to get this now. However, I just created a project based on what you said above. So I have Advanced Yield Test Script and Sphere:

using UnityEngine;
using System.Collections;

public class AdvancedYieldTest : MonoBehaviour {

public GameObject referenceToObject;
private static Sphere referenceToScriptForObject;

// Use this for initialization
void Start () {

	// Reference the script on the sphere
	referenceToScriptForObject = referenceToObject.GetComponent<Sphere>();
}

// Update is called once per frame
void Update () {

	if ( Input.GetMouseButtonUp ( 0 ) )
 	{
		StaticFunctionTest();
 	}
	
}

private static void StaticFunctionTest()	
{
	Debug.Log("Called static function.");
    referenceToScriptForObject.AccessToUpdatePosition();

}

using UnityEngine;
using System.Collections;

public class Sphere : MonoBehaviour {

// Use this for initialization
void Start () {

}



public IEnumerator AccessToUpdatePosition()
{
	Debug.Log("AccessToUpdatePosition");
	
	Vector3 target = new Vector3 ( 1.0f, 0.0f, 0.0f );
	
	
	// wait until it's reached taget position
	yield return StartCoroutine( UpdatePosition( target ) );	
	
	//Now do something else
	Debug.Log("ITS ARRIVED!!!!!");
	
}



// Test IENumerator function
private IEnumerator UpdatePosition( Vector3 target)
{
	Debug.Log("UpdatePosition");
	transform.Translate ( 0.2f, 0.0f, 0.0f );
	
	while ( transform.position.x!=target.x )
	{
		// This waits for next frame
	 yield return 0;	
	}
	
	
	
}

}

}

Which I think is very close to your example above. The issue is that when I run and step through it, it gets to StaticFunctionTest(), logs out “Called static function”, enters AccessToUpdatePosition() on the actual object but then actually returns without even logging out Debug.Log(“AccessToUpdatePosition”);

Really struggling to understand why?
Cheers