Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by CrucibleLab · Apr 16, 2015 at 10:35 PM · coroutinenavmeshagentwaitforseconds

Choking on WaitForSeconds coroutine (solved)

Gents - I have a Navmesh Agent roaming around a map. When the player approaches within a certain distance from the agent, the agent goes into a "suspicious" mode and pauses for 3 seconds. Within that 3-second window, if the player goes outside the bound, then the agent moves on. Otherwise, the agent comes after the player.

Here's the corresponding code:

 void Update() {
     distanceToPlayer = CheckDistance();   // simply returning distance between the agent & player
     if (distanceToPlayer < suspicionDistance) {
         agent.Stop();    // make agent appear to be thinking...
         feelingSuspicious = true;

         StartCoroutine(ResolveSuspicion(3.0f)); // make agent stand still for 3 seconds until next move
         if (chasingPlayer) {
             agent.destination = player.transform.position; // get the intruder!
         } else {
             agent.Resume(); // hmm, must've been a rat...
         }
         ....
     }
     ....
 }

 IEnumerator ResolveSuspicion(float duration) {
     yield return new WaitForSeconds(duration);
     float distanceToPlayer = CheckDistance();
     if (distanceToPlayer < suspicionDistance) {
         chasingPlayer = true;
     }
 }

Everything works as intended, except the agent is supposed to pause for 3 seconds as soon as the player steps inside the 'suspicionDistance' but it doesn't -- it just comes straight to the player without a pause. I double checked the values for the various distance variables and they are all correct.

I'm thinking I must be misusing the WaitForSeconds method, but can't seem to figure out how to go about making it work.

===== (UPDATE) =====

For anyone who's interested, here's my solution that seems to work:

 IEnumerator ResolveSuspicion(float duration) {

     agent.Stop();
     feelingSuspicious = true;

     yield return new WaitForSeconds(duration);

     float distanceToPlayer = CheckDistance();
     if (distanceToPlayer < suspicionDistance) {
         chasingPlayer = true;
     } else {
         agent.Resume();
     }
 }

 void Update() {
     distanceToPlayer = CheckDistance();

     if (distanceToPlayer < suspicionDistance) {
         if (!chasingPlayer) {
             StartCoroutine(ResolveSuspicion(3.0f));
         } else {
             agent.destination = player.transform.position;
             agent.Resume();
         }
         ....
     } else {
         if (feelingSuspicious) {
             feelingSuspicious = false;
             agent.Resume();
         }
     }
 }

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Addyarb · Apr 16, 2015 at 10:48 PM

In my experience, adding a bool to check whether or not your coroutine is already running is the best way to go.

Try this.

 bool runningCoroutine;
 
  void Update() {
      distanceToPlayer = CheckDistance();   // simply returning distance between the agent & player
      if (distanceToPlayer < suspicionDistance) {
          agent.Stop();    // make agent appear to be thinking...
          feelingSuspicious = true;
  if(!runningCoroutine)
          StartCoroutine(ResolveSuspicion(3.0f)); // make agent stand still for 3 seconds until next move
          if (chasingPlayer) {
              agent.destination = player.transform.position; // get the intruder!
          } else {
              agent.Resume(); // hmm, must've been a rat...
          }
          ....
      }
      ....
  }
  
  IEnumerator ResolveSuspicion(float duration) {
      yield return new WaitForSeconds(duration);
      float distanceToPlayer = CheckDistance();
      if (distanceToPlayer < suspicionDistance) {
          chasingPlayer = true;
      }
      runningCoroutine = false;
  }

Comment
Add comment · Show 11 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image CrucibleLab · Apr 17, 2015 at 12:07 AM 0
Share

Per your suggestion, here's what I tried:

 private bool feelingSuspicious = false;

 void Update() {
     distanceToPlayer = CheckDistance();
     if (distanceToPlayer < distanceSuspicion) {
         agent.Stop();

         if (!feelingSuspicious) {
             StartCoroutine(ResolveSuspicion(3f));
         }
         ... // rest of the code is the same as before
 }

 IEnumerator ResolveSuspicion(float duration) {
     feelingSuspicious = true;
     yield return new WaitForSeconds(duration);
     float distanceToPlayer = CheckDistance();
     if (distanceToPlayer < distanceSuspicion) {
         chasingPlayer = true;
     }
     feelingSuspicious = false;
 }

I think this should take care of it, but it still produces the same result. :/

avatar image Addyarb · Apr 17, 2015 at 01:19 AM 0
Share

Can you confirm that you're not altering the "chasingPlayer" bool anywhere else in the script?

avatar image CrucibleLab · Apr 17, 2015 at 01:26 AM 0
Share

Yes, I confirm that 'chasingPlayer' is being altered only at line 19 and nowhere else in my entire code.

avatar image Addyarb · Apr 17, 2015 at 01:42 AM 0
Share

Is it the case that the first time around, your character waits 3 seconds, but then doesn't after the first time? I can't find any feasible way that he could just follow the target unless you're somehow using SetDestination() before you call your coroutine.

avatar image CrucibleLab · Apr 17, 2015 at 01:54 AM 0
Share

The agent doesn't pause at all - not even the first time around. What I also noticed is that even if I comment out the "chasingPlayer = true" part, the agent keeps on moving as if the player isn't there. I think the agent is continuing to stay on its predefined path, but I thought the "agent.Stop()" line was supposed to stop it.

Show more comments
avatar image
0

Answer by Eric5h5 · Apr 16, 2015 at 10:40 PM

You're starting a new coroutine every frame in Update as long as distanceToPlayer < suspicionDistance. In general it's not a good idea to mix Update with coroutines; it's technically possible, but requires what usually ends up being a lot of convoluted code. I would recommend removing Update and using only coroutines.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image CrucibleLab · Apr 16, 2015 at 11:59 PM 0
Share

While what you explained makes perfect sense, I'm not sure how I can refactor my code in a way that I can remove Update altogether. Don't I need Update to at least check on the distance of the agent and player on a real-time basis?

avatar image
0

Answer by Zild · Apr 17, 2015 at 06:50 AM

The problem is that a coroutine is another bit of code (routine) that runs at the same time as the code following the call to it (co). It is NOT a wait or a timer, but rather a second set of code running in parallel.

So take the following code of yours:

    StartCoroutine(ResolveSuspicion(3.0f)); // make agent stand still for 3 seconds until next move
          if (chasingPlayer) {
              agent.destination = player.transform.position; // get the intruder!
          } else {
              agent.Resume(); // hmm, must've been a rat...
          }

What this actually does is continue to the if / else statement immediately, regardless of the coroutine's code. So it will either automatically go straight to the destination or run agent.Resume(), depending on whatever value was already set for chasingPlayer.

Try putting that if / else statement into the coroutine itself, located after the yield - that way it will act as a timer and not be fired off until after duration seconds.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AlwaysSunny · Apr 17, 2015 at 06:52 AM 0
Share

The rest of the answer looks okay, but coroutines are not run in parallel. (I promise).

Have a look here to confirm: http://docs.unity3d.com/$$anonymous$$anual/ExecutionOrder.html

The only way to create code running in parallel involves worker threads.

avatar image CrucibleLab · Apr 17, 2015 at 01:45 PM 0
Share

I think the last code snippet I added to the comment section does essentially what you suggested here. I currently have the "if (chasingPlayer) { ..." block commented out, and the ResolveSuspicion function contains the modified if-then-else block that should take care of agent's next movement. Or at least that's my understanding.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to make loop with call to IEnumerator actually pause? 2 Answers

WaitForSeconds Not Working 4 Answers

Problem with coroutine 2 Answers

How to implement a "wait" after an animation has finished? 2 Answers

What is the best method for setting up a variable wait time in a coroutine? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges