Sultan Khan
Sultan Khan

Reputation: 27

How can I run StartCoroutine once?

The code in my script works fine. But sometimes it does not drop after I contact the rigid body collides. When it touches another corner, it restarts the StartCoroutine. I want to run it once to get ahead of it. How can I get it? (More descriptive: In my game, a ball is falling from above, and it stops for 3 seconds when hit by obstacles. I do not want it to stop in that obstacle again after it has hit once.

public void OnCollisionEnter2D(Collision2D col)
{

     if (col.collider.CompareTag("Player"))
     {
         hitEffect.transform.position = col.contacts[0].point;
         hitEffect.gameObject.SetActive(true);
         GameManager.Instance.playerController.anim.Squeeze();
         col.gameObject.GetComponent<Rigidbody2D>().simulated = false;
         StartCoroutine (SetKinematic_Coroutine(col));
     }
}

public IEnumerator SetKinematic_Coroutine(Collision2D col) 
{
     yield return new WaitForSeconds(1f);
     col.gameObject.GetComponent<Rigidbody2D>().simulated = true;
}

Upvotes: 1

Views: 1787

Answers (3)

Everts
Everts

Reputation: 10701

Best way for preventing multi call of a coroutine is to use a reference:

private IEnumerator coroutine = null;

private void Method()
{
    if(condition == true && this coroutine == null)
    {
        this.coroutine = MyCoroutine();
        StartCoroutine(this.coroutine);
    }
}

private IEnumerator MyCoroutine()
{
     yield return null;
     this.coroutine = null; // Set it back to null when leaving the coroutine.
}

When the condition is met and the coroutine is null (you are not running it already), it will assign to the reference and call the starting of the coroutine. While the coroutine is running, this.coroutine is not null and the double condition cannot be met anymore. When the coroutine is done, this.coroutine is set to null so next time the double condition is run, they will be both true.

You can also use a basic boolean for flag, but the usage of the IEnumerator reference can also be used to cancel.

Upvotes: 3

Maglethong Spirr
Maglethong Spirr

Reputation: 443

Add a list of objects already hit by it and, for every hit, check if the object it is colliding with is in the list, if not add it and run the code.

private List<Collider2D> collided = new List<Collider2D>();

public void OnCollisionEnter2D(Collision2D col) {

    if (col.collider.CompareTag("Player") && !collided.Contains(col.collider)) {
        collided.Add(col.collider);
        // ...    

The Contains call might give you trouble if to many colliders are added to the list frequently, but otherwise this should do it.

Upvotes: 1

CaTs
CaTs

Reputation: 1323

You could turn the collider of the ball off whilst it is stopped so it can't receive any more hits during that time.

 public IEnumerator SetKinematic_Coroutine(Collision2D col) 
 {
     //turn the collider off
    col.gameObject.GetComponent<Collider2D>().enabled = false;

     yield return new WaitForSeconds(1f);
     col.gameObject.GetComponent<Rigidbody2D>().simulated = true;

     //turn the collider back on after we have waited 
    col.gameObject.GetComponent<Collider2D>().enabled = true;
 }

Upvotes: 2

Related Questions