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 AntLewis · Nov 22, 2011 at 09:19 PM · startcoroutine

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

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
1

Answer by Bunny83 · Nov 22, 2011 at 09:48 PM

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");
 }
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 AntLewis · Nov 23, 2011 at 08:44 AM 0
Share

Thanks for the comments guys - the other issues still remains however, this:

StartCoroutine ( referenceToSphereOne.IETESTUpdatePosition() );

still returns the same error as I described above. $$anonymous$$any thanks for your time.

avatar image Bunny83 · Nov 25, 2011 at 05:03 PM 0
Share

Where do you execute this line:

 StartCoroutine ( referenceToSphereOne.IETESTUpdatePosition() );

?
It looks like you try to call StartCoroutine from a static function? You know that StartCoroutine is a member-function of $$anonymous$$onoBehaviour? Coroutines always run on $$anonymous$$onoBehaviour-instances. Usually you call StartCoroutine from inside a $$anonymous$$onoBehaviour. When you have your code in a static function (that doesn't belong to any instance) you have to provide a $$anonymous$$onoBehaviour instance.

Beside this technical fact, i guess you also want to run the coroutine on the Sphere object itself...

You have two ways to accomplish that:

  1. Call StartCoroutine of your Sphere instance (Sphere is a class that inherits from $$anonymous$$onoBehaviour) by using the reference to your instance

  2. Provide a seperate function that starts your coroutine which can be called from outside.

Solution 1:
In your static function call StartCoroutine this way:

 referenceToSphereOne.StartCoroutine ( referenceToSphereOne.IETESTUpdatePosition() );

Solution 2:
This is the cleaner one since it avoids the ugly reference madness:

 // In your Sphere script:
 private IEnumerator IETESTUpdatePosition()
 {
     // Your coroutine is now private since only the class itself is going to use it.
     // [...]
 }
 
 public void TESTUpdatePosition()
 {
     StartCoroutine(IETESTUpdatePosition());
 }
 
 // In your static function you can use the TESTUpdatePosition function of your Sphere class like that:
 
 referenceToSphereOne.TESTUpdatePosition();
avatar image
0

Answer by Eric5h5 · Nov 22, 2011 at 09:45 PM

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.

Comment
Add comment · 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
0

Answer by AntLewis · Nov 30, 2011 at 08:51 AM

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

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 Bunny83 · Nov 30, 2011 at 02:52 PM 0
Share

$$anonymous$$y "TESTUpdatePosition" is NOT a coroutine. Coroutines are something totally different than normal functions. Coroutines are also called generator functions. The coroutine itself just return an object (IEnumerator) which can be used to "iterate" through the code inside your coroutine. This "iteration" is done by Unity but you have to pass the IEnumerator to StartCoroutine() so Unity can actually run the coroutine.

If you just call your generator function without StartCoroutine it will return the IEnumerator object and you throw it away.

Your "StaticFunctionTest" won't work since AccessToUpdatePosition() is also a coroutine / generator function which have to be used along with StartCoroutine.

After you start a coroutine it runs on it's own. You can't wait in normal functions for it's completion, only in other coroutines.

If you want to understand how coroutines work you may study this excellent custom coroutine scheduler. Also (if you have missed it in the post) check out the blog article about coroutines.

btw. Answers should exclusively used for answers. I know it's a pain to write such a long post in a comment but you can use almost the same features in comments, you just don't have the nice helper-buttons on top.

avatar image Bunny83 · Nov 30, 2011 at 03:03 PM 0
Share

Just saw your UpdatePosition function. Transform.Translate will immediately move your object by the given amount. Your loop waits until the x coordinate will match the targets x position but inside the loop you don't move your object. Beside that if you increment the position each frame by 0.2 it won't reach the target position due to float inaccuarcy. 5.7 is not the same as 5.69999999 or 5.70000001 even when it's visually the same.

Your first lerp approach will reduce the step each frame as it comes closer to the target. This results in a decelerated movement so it never goes beond the target. But even with $$anonymous$$athf.Approximately it could take quite a time to reach "equality".

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

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Invoke a Coroutine From OnCollisionEnter 1 Answer

Is there anything like "StartCoroutine", but for a non MonoBehaviour? 2 Answers

Run Coroutine only once 1 Answer

GET Request dont save data 0 Answers

Yield position within while loop in 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