Search Unity

How should I start coroutine only once each time and how can I make an object ping pong ?

Discussion in 'Scripting' started by SharonL75, Oct 24, 2020.

  1. SharonL75

    SharonL75

    Joined:
    Aug 13, 2020
    Posts:
    91
    Inside OnAnimatorIK :

    Code (csharp):
    1.  
    2. if (finalLookWeight > 0.95f) // here you can play with a value between 0.95f -> 1.0f
    3.                 {
    4.                     if (primaryTarget.interactableMode == InteractableItem.InteractableMode.Action
    5.                         && IsAlreadyThrown == false)
    6.                     {
    7.                         // call your funtion to shoot something here
    8.                         StartCoroutine(ThrowObject(objToThrow.transform, primaryTarget.transform, throwSpeed));
    9.                         IsAlreadyThrown = true;
    10.                     }
    11.                 }
    12.  
    I'm using a flag helper to make it start the Coroutine one time.
    but I also want to be able to call from other scripts or methods and change the helper flag IsAlreadyThrown back to false so it will throw the object also in other times in the game.

    Without the flag it will call the StartCoroutine nonstop.
    The flag IsAlreadyThrown is global variable and init as false.

    Another problem is how to throw the object to the target and then wait for the object to do something for now it can be everything like waiting some seconds or do some effects but the goal is to send the object to the target do some stuff and then send the object back to the original position he was sent from :

    Inside the ThrowObject method I did :

    Code (csharp):
    1.  
    2. IEnumerator ThrowObject(Transform objectToMove, Transform toPosition, float duration)
    3.     {
    4.         float counter = 0;
    5.  
    6.         while (counter < duration)
    7.         {
    8.             counter += Time.deltaTime;
    9.             Vector3 currentPos = objectToMove.position;
    10.  
    11.             float time = Vector3.Distance(currentPos, toPosition.position) / (duration - counter) * Time.deltaTime;
    12.  
    13.             objectToMove.position = Vector3.MoveTowards(currentPos, toPosition.position, time);
    14.  
    15.             yield return null;
    16.         }
    17.  
    18.         //StartCoroutine(ThrowBack(objectToMove, toPosition, duration));
    19.     }
    20.  
    21. And then :
    22.  
    23. [code]
    24.     IEnumerator ThrowBack(Transform objectToMove, Transform toPosition, float duration)
    25.     {
    26.         float counter = 0;
    27.  
    28.         while (counter < duration)
    29.         {
    30.             counter += Time.deltaTime;
    31.             Vector3 currentPos = objectToMove.position;
    32.  
    33.             float time = Vector3.Distance(currentPos, toPosition.position) / (duration - counter) * Time.deltaTime;
    34.  
    35.             objectToMove.position = Vector3.MoveTowards(toPosition.position, currentPos, time);
    36.  
    37.             yield return null;
    38.         }
    39.     }
    40.  
    I tried to use and start the second Coroutine but it's just did nothing the object didn;t move back to the original position he was thrown from the object just not moving at all.

    Code (csharp):
    1.  
    2. StartCoroutine(ThrowBack(objectToMove, toPosition, duration));
    3.  
     
  2. Ravenholmn

    Ravenholmn

    Joined:
    Mar 4, 2022
    Posts:
    1
    This is an old post, so I'm replying for anybody who might stumble upon this.

    Either set the bool true before the coroutine or at the start of the coroutine.

    To make the object wait where it was thrown you can add a new WaitForSeconds at the end of the coroutine with a set time. Now, a set amount of time might seem a bad idea but here's what you can do about it:

    Code (CSharp):
    1. private Coroutine _referenceCoroutine;
    2.  
    3. public void StartReferenceCoroutine()
    4. {
    5.  
    6.     //this creates a single coroutine named "referenceCoroutine" that you can stop later
    7.     _referenceCoroutine = StartCoroutine(MyCoroutine());
    8.  
    9. }
    10.  
    11. public void StopReferenceCoroutine()
    12. {
    13.  
    14.     //here we are able stop the coroutine at will
    15.     StopCoroutine(_referenceCoroutine);
    16.  
    17. }
    18.  
    19. IEnumerator MyCoroutine()
    20. {
    21.  
    22.     //coroutine functions
    23.  
    24. }
    This enables you to stop the coroutine at will, therefore you can stop the ThrowObject coroutine at any time and then start the ThrowBack coroutine, even in the middle of it. You can check if the object is thrown with a bool at the end of the coroutine (before the WaitForSeconds) and then only make StopReferenceCoroutine work if the bool is true.

    As for ping pong, Mathf has a cool function called Mathf.PingPong(t, length) where t is a self incrementing value like Time.deltaTime, and length is the max value. This function ping pongs from 0 to length using t and returns as a float value. Here's an example:

    Code (CSharp):
    1. IEnumerator RotateCoroutine()
    2.     {
    3.         WaitForEndOfFrame wait = new WaitForEndOfFrame();
    4.         float timer = 0f;
    5.         float duration = 2f;
    6.  
    7.         while (timer < duration)
    8.         {
    9.             timer += Time.deltaTime;
    10.            
    11.            
    12.            transform.rotation = Quaternion.Euler(0f, 0f, Mathf.PingPong(timer / duration * 300, 60f) - 30f);
    13.            
    14.             yield return wait; //Also I have noticed, do not use null for ANYTHING. For yield return null use yield return WaitForEndOfFrame instead, and for null checks use if (var != default) instead. default means the same with null, but checking for null is more expensive.
    15.         }
    16.     }