Reputation: 27
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
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
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
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