Paco Martos Triguero
Paco Martos Triguero

Reputation: 167

Wait for a coroutine to finish before moving on with the function C# Unity

I was working on making a unit move through a grid in Unity2d. I got the movement to work without problems. I would want the function MovePlayer to wait until the coroutine is finished before moving on, so the program will wait until the player has finished the movement before issuing more orders.

Here is my code: public class Player : MonoBehaviour {

public Vector3 position;
private Vector3 targetPosition;

private float speed;

void Awake ()
{
    speed = 2.0f;
    position = gameObject.transform.position;
    targetPosition = position;
    GameManager.instance.AddPlayerToList(this);                     //Register this player with our instance of GameManager by adding it to a list of Player objects. 
}

//Function that moves the player, takes a list of nodes as path
public void MovePlayer(List<Node> path)
{
    StartCoroutine(SmoothMovement(path));
    //Next step should wait until SmoothMovement is finished
}

private IEnumerator SmoothMovement(List<Node> path)
{
    float step = speed * Time.deltaTime;

    for (int i = 0; i < path.Count; i++)
    {
        targetPosition = new Vector3(path[i].coordinatesX, path[i].coordinatesY, 0f);

        float sqrRemainingDistance = (transform.position - targetPosition).sqrMagnitude;

        while (sqrRemainingDistance > float.Epsilon)
        {
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
            sqrRemainingDistance = (transform.position - targetPosition).sqrMagnitude;
            yield return null;
        }

        position = transform.position;
    }

}

Upvotes: 13

Views: 41679

Answers (3)

Eraph
Eraph

Reputation: 1029

You can encapsulate the two calls into a single coroutine, with both of them using yield return to ensure they don't run in parallel.

public void MovePlayer(List<Node> path)
{
    StartCoroutine(MovePlayerCoroutine(path));
}

private IEnumerator MovePlayerCoroutine(List<Node> path)
{
    yield return SmoothMovement(path);
    yield return NextSteps();
}

private IEnumerator SmoothMovement(List<Node> path)
{
    ...
}

private IEnumerator NextSteps()
{
    ...
}

Upvotes: 0

Mickey Pearson
Mickey Pearson

Reputation: 191

Also if this Question is answered, some people cannot use the solution from itectori, so here is my solution:

You could do

yield return StartCoroutine(yourCoroutine);

But in this case your function can not return void.

Upvotes: 4

itectori
itectori

Reputation: 150

You can not wait for a coroutine in a function in the main thread, otherwise your game will freeze until your function ends.

Why don't you call your next step at the end of your coroutine?

private IEnumerator SmoothMovement(List<Node> path)
{
    float step = speed * Time.deltaTime;

    for (int i = 0; i < path.Count; i++)
    {
        targetPosition = new Vector3(path[i].coordinatesX, path[i].coordinatesY, 0f);

        float sqrRemainingDistance = (transform.position - targetPosition).sqrMagnitude;

        while (sqrRemainingDistance > float.Epsilon)
        {
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
            sqrRemainingDistance = (transform.position - targetPosition).sqrMagnitude;
            yield return null;
        }

        position = transform.position;
    }
    //Next Step
}

Upvotes: 10

Related Questions