1
\$\begingroup\$

I made a scenario that shooting a bullets on crates make them both bounce nicely (both the bullet and crates are RigidBody2D & Colliders). When I use OnCollisionEnter2D to destroy the bullet when it hits the crate then the bullet destroyed before it pass the force to the crate and thus the crate stay still and not move physically...

How to make the crate move because of the bullet hit and also make the bullet to destroyed? There is more elegant way from just destroy the bullet a frame after the hit?

\$\endgroup\$
1
  • \$\begingroup\$ I don't know Unity/C#, but could you somehow mark the bullet for deletion (so you end up deleting it later) that way it still has time to perform physics calculations on the crate? \$\endgroup\$
    – CodeNMore
    Mar 6, 2016 at 17:59

3 Answers 3

1
\$\begingroup\$

An easy workaround is to disable SpriteRenderer component In OnCollisionEnter2D and you can then destroy bullet let say after half or a second. Something like,

void OnCollisionEnter2D(Collision2D other)
{
    // Assuming that your crate has tag of "crate"
    if (other.gameObject.tag == "crate")
    {
        GetComponent<SpriteRenderer>().enabled = false;
        Destroy(gameObject, 0.5f);
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ I object to this answer. Any code that depends on an arbitrary time makes me feel uneasy. \$\endgroup\$
    – Evorlor
    Mar 6, 2016 at 22:08
  • \$\begingroup\$ Me too, but it is not anything like spawning or something else like this, in other words your game-logic is not dependent on time. If bullet destroys more or less 0.5f seconds then that'd be alright anyways. \$\endgroup\$ Mar 7, 2016 at 4:15
  • \$\begingroup\$ There are always side effects. For examples, FindObjectsOfType<Bullet>().Length is inaccurate. It will run into things half second after it is supposedly despawned, and make the player WTF. If you are Mario and can only have two fire powers at once, there is a half second delay before you can shoot the third. Etc. The smallest misstep is always greater than what is apparent on top. Even my answer above can lead to bugs similar this. \$\endgroup\$
    – Evorlor
    Mar 7, 2016 at 13:36
1
\$\begingroup\$

Here are two similar strategies with tiny differences. I suggest the second approach.

The physics will happen the next FixedUpdate. So wait until that FixedUpdate is over. We can do this by waiting for FixedUpdate twice. The first pass will take us to when the physics start taking place. The second pass will take us to the FixedUpdate after the physics have completed.

void OnCollisionEnter2D(Collision2D other)
{
    StartCoroutine(DestroyAfterPhysics());
}

private IEnumerator DestroyAfterPhysics()
{
    yield return new WaitForFixedUpdate();
    yield return new WaitForFixedUpdate();
    Destroy(gameObject);
}

That code makes the assumption that all current physics will be dealt with during the immediate FixedUpdate. We can avoid this assumption and clean the code a bit by waiting for the maximum delta time. This version of the code will assure success, but possibly at the loss of an insignificant amount of time:

void OnCollisionEnter2D(Collision2D other)
{
    Destroy(gameObject, Time.maximumDeltaTime));
}

This is not a flawless approach, and I would be interested to see other ideas. For example, if you check to see if the bullet exists the frame after the collision, it could return a false positive.

\$\endgroup\$
0
\$\begingroup\$

This was the first result when I was trying to figure it out myself, so I wanted to post my solution after I got it working.

Not sure of the consequences of this just yet though.

In my case, I wanted a bullet impact to destroy the bullet after the collision made the receiving rigid body react to the collision.

Instead of:

void OnCollisionEnter(Collision collision)
    {
        AttemptToDamage(collision);
        Destroy(gameObject);
    }

Try

void OnCollisionEnter(Collision collision)
    {
        AttemptToDamage(collision);
    }
void OnCollisionStay(Collision collision)
    {
        Destroy(gameObject);
    }

I could be getting this wrong so someone please correct me if I'm mistaken, but my take of it is sort of like OnEnable vs Update, where OnCollisionEnter fires before the rest of the physics step, whereas OnCollisionStay fires after.

Either that or because my bullet is still colliding into the next physics step, OnCollisionStay fires anyway.

In both cases though, it does seem like the bullet both interacts with rigidbody and then subsequently is destroyed.

Hopefully this helps... 6 years later.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .