Coroutine breaks after WaitUntil is called.

I have a code that uses OnClick to send a navmesh agent to a pre-placed destination point. This is for a “virtual tour” of sorts. I also want a “Guided tour” routine that just cycles through all the destination points.

Code:

public class UIMotor : MonoBehaviour {

public Button m_dest1, m_dest2, m_guideTour;
private NavMeshAgent agent;
public Transform dest1, dest2;
public Transform[] waypoints;
public Vector3 destination;

// Use this for initialization
void Start () {

    agent = GetComponent<NavMeshAgent>();
    destination = agent.destination;

    Button btn1 = m_dest1.GetComponent<Button>();
    Button btn2 = m_dest2.GetComponent<Button>();
    //Button btn3 = m_guideTour.GetComponent<Button>();

    btn1.onClick.AddListener(GoToDest1);
    btn2.onClick.AddListener(GoToDest2);
    //btn3.onClick.AddListener(GuideTour);
}

// Update is called once per frame
void Update () {
    Button btn3 = m_guideTour.GetComponent<Button>();
    btn3.onClick.AddListener(GuideTour);
}

void GoToDest1()
{
    agent.destination = dest1.position;
}

void GoToDest2()
{
    agent.destination = dest2.position;
}

void GuideTour()
{
    StartCoroutine(GuidedTour());
}

private bool AtPoint()
{
    if(Vector3.Distance(destination, dest1.position) <= 0.5f )
    {
        return true;
    }
    else
    {
        return false;
    }
}

IEnumerator GuidedTour()
{
    agent.destination = dest1.position;
    yield return new WaitUntil(AtPoint);
    agent.destination = dest2.position;
    yield return new WaitForSecondsRealtime(10);
    agent.destination = dest1.position;

}

}

The coroutine works if I just do WaitForSecondsRealtime between each destination, but that’s not great since I don’t want to test each travel time by hand. With the code above it does go to destination 1, but just stays there. Did the same even with a simple destination == target.postion bool.

Is the code broken or am I now missing something to restart the code after the WaitUntil?

I think that the problem it’s this:
`

  1. // Update is called once per frame
    void Update () {
    Button btn3 = m_guideTour.GetComponent();
    btn3.onClick.AddListener(GuideTour);
    }
    `
    You are adding a new listener every frame. So actually when the button it’s pressed you start lots of coroutines. Move those two lines into Start and give it a go.

Apart from what Pakillottk said you check the distance between “destination” and “dest1.position”. I guess that “dest1.position” is actually a fix destination object. “destination” is only set in the Start method once and never changed again. So when you start the coroutine you compare two constant values against each other. So if the initial position of your agent is further away from dest1.position than 0.5 the coroutine will never continue as you are stuck in that check. If it’s actually smaller than 0.5 the coroutine will immediately go to dest2 after one frame.

You just said your coroutine “breaks” and we have no idea what that means to you. Does it throw an exception? Does it do nothing? Does it do something unexpected? If so what exactly does it do?

It’s your code so you have to know what it is supposed to do. So only you can tell the difference from the expected behaviour and the actual behaviour.

I guess that you actually meant to do:

if(Vector3.Distance(agent.destination, agent.nextPosition) <= 0.5f)

However you could simply use the remainingDistance of the navmesh agent instead

if(agent.remainingDistance <= 0.5f)

Though keep in mind that the agent has a stoppingDistance. Maybe your stopping distance is larger than your 0.5. In that case the agent could stop before he gets close enough.