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 Ashish4241 · Oct 15, 2014 at 12:13 PM · c#coroutineyieldcoroutinesstartcoroutine

Coroutines and states

I have studied coroutines from wikipedia,Unity documentation and this unite 2013 video.

Now the problem is as Wikipedia explains Coroutines are able to save states(including local variables).In the video Devin Horsman shows that a state machine can be implemented using Coroutines at 7:54 in the video he shows implementation of a coroutine setup to work as a state machine.He explains that coroutines can "remember state" which is useful as it avoids having class level variables and avoid having cluttered code. So I tried implementing a very basic follower where the follows the enemy while in range and then goes to wait if out of range using coroutines as-

 using UnityEngine;
 using System.Collections;
 
     public class Enemy : MonoBehaviour 
     {
         private GameObject player;
         private float DangerDistance = 8.0f;
         public float EnemySpeed = 1.0f;
         // Use this for initialization
         void Awake()
         {
             player = GameObject.FindGameObjectWithTag("playerBall");
     
         }
         bool inDangerDistance()
         {
     
             Vector2 playerpos = new Vector2(player.transform.position.x,player.transform.position.z);
             Vector2 mine = new Vector2(transform.position.x,transform.position.z);
             Vector2 dotter = new Vector2(transform.forward.x,transform.forward.z);
             //Debug.Log(Vector2.Dot((playerpos-mine).normalized,dotter.normalized));
     
             return Vector2.Distance(playerpos,mine)<=DangerDistance && nearEquals(Vector2.Dot((playerpos-mine).normalized,dotter.normalized),1);
         }
     
         bool nearEquals(float first,float second)
         {
             return Mathf.Abs(first-second)<=0.2f;
         }
         IEnumerator search()
         {
             while(true)
             {
                 if(inDangerDistance())
                 {
                     yield return StartCoroutine(follow());
                     
                 }
                 transform.Rotate(0,90*Time.deltaTime,0);
                        
                 yield return null;
             }
     
         }
         IEnumerator follow()
         {    
             
             Vector2 playerpos = new Vector2(player.transform.position.x,player.transform.position.z);
             
             Vector2 mine = new Vector2(transform.position.x,transform.position.z);
             while(true)
             {
             while(inDangerDistance())
             {
                     
                 
                 playerpos.x = player.transform.position.x;
                 playerpos.y = player.transform.position.z;
                 mine.x = transform.position.x;
                 mine.y = transform.position.z;
                 Vector3 v1 = new Vector3(playerpos.x,0,playerpos.y)-new Vector3(mine.x,0,mine.y);
                 transform.forward = v1;
                 transform.Translate((playerpos.x-mine.x)*Time.deltaTime*EnemySpeed,0,(playerpos.y-mine.y)*Time.deltaTime*EnemySpeed,relativeTo:Space.World);
     
                 yield return null;
             }
     
             yield return StartCoroutine(search());
             Debug.Log("yoohoo");
             }
         }
     
     
     
     
     
     
         void Start() 
         {
     
             StartCoroutine(search());
         }
         
         
     }

Now the problem I notice with this approach is there is no actual State preserved as I switch from search to follow and vice versa as StartCoroutine builds a new Coroutine object and defeats the purpose of preservation("yoohoo" is never printed in follow()).So what advantage really Coroutines have other than using WaitforSeconds() if they could not preserve state or there is something wrong in the video or I am completely wrong?Thanks for help.

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

1 Reply

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

Answer by Kiwasi · Oct 16, 2014 at 02:58 AM

You've essentially built an infinite chain of coroutines. Search will start Follow which starts Search which starts Follow... ad infinitum.

Take the while(true) condition out of Follow. Remove line 68 (the call to Search) and it should function closer to a FSM.

Another alternative is to have a master coroutine. Take the while (true) out of both and do something like this (call from Start). Remove the calls to other coroutines from Follow and Start. And have them only exit their loop when there transition condition is met.

 IEnumerator FSM (){
     while (true){
         yield return StartCoroutine (Search());
         yield return StartCoroutine (Follow());
     }
 }

Comment
Add comment · Show 4 · 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 Ashish4241 · Oct 16, 2014 at 03:12 AM 0
Share

the problem in the code u gave is still there as new Coroutine objects will be created by startCoroutine and I wont be able to save the state as such of search and follow.Please see the video I talk about.

avatar image Bunny83 · Oct 16, 2014 at 03:57 AM 0
Share

@Ashish4241: You have to be careful with the definition of coroutines since there are huge differences. Unity (and C#) doesn't have true coroutines. C# / .NET provides generators, so called semicoroutines. They don't allow you to specify the re-entry point. You always come back where you left off.

Generators in .NET are actually implemented as a FS$$anonymous$$ with a switch statement. There used to be a great blog post with great examples how the generated IEnumerator class looks like. However the blog doesn't exist anymore, but there are others like this one.

You're using your coroutine just like subroutines. You're blocking the coroutine until the subroutine has finished. The point of using a coroutine for some kind of FS$$anonymous$$ is usually to have everything inside that coroutine. You can use nested while loops to stay in a certain state, break out if your done, ect... You can have temporary "update loops" inside the coroutine. That allows you to simply structure your code almost like pseude code.

Another way is to have for each state a seperate coroutine and run them all at once (you just start them all once in Start). Each coroutine simply idles by being trapped in a while loop with a yield return null until the while loop exits and the actual action / state this coroutine represents becomes active. However such an approach isn't very flexible.

Personally i never used coroutines to implement a complete FS$$anonymous$$. They come in handy when you have actions that should be executed in order but each action might take several frames to complete.

avatar image Ashish4241 · Oct 16, 2014 at 04:56 AM 0
Share

So whats shown in the video at 7:54 is just using coroutines for nothing more than subroutines which execute over frames?

avatar image Kiwasi · Oct 16, 2014 at 05:05 AM 0
Share

Updated my code to show my original intent. Sorry for the mixup.

@Ashish4241 Yes. That is the whole point of a coroutine.

If you want a massive complex FS$$anonymous$$ then you should look at implementing a specific framework (UnityGems has one) or a graphical FS$$anonymous$$ (Playmaker)

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

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Trouble Resuming after Yielding while Inside Coroutine 1 Answer

What am I doing wrong with IEnumerator? 1 Answer

StartCoroutine() and yield return www does not work with Unity Web Player build 0 Answers

WaitForSeconds doesn't seem to work. 1 Answer

Using yield without StartCoroutine() in C# 3 Answers


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