Arrow passing through objects

I’m having a little trouble with my arrow script. It’s supposed to:

  • follow an arc
  • stop when it hits a target
  • apply its force to that target

Of which it sort of does all three, but the latter two not really consistently.

I’ve attached images of its misbehaviour - notably, that at high speeds it often passes through other colliders before stopping. I’ve tried playing around with FixedUpdate and similar but surely this is a common problem if it’s that it’s moving too fast?
8640855--1162188--Arrow Passing through object.jpg 8640855--1162191--Arrow passing through wall.jpg 8640855--1162194--Arrow floating on Potion.jpg

The script that powers it is below:

public class ArrowBehaviour : MonoBehaviour
{

    private Rigidbody2D body;
    private Collider2D arrowCollider;
    [SerializeField] private float massOffset;
    [SerializeField] int destroyTimeSet;
    private bool _followArc;
    private bool _firstFrame;
    private int destroyTimer;
   

    private void Awake()
    {
        body = GetComponent<Rigidbody2D>();
        arrowCollider = GetComponent<Collider2D>();
    }


    private void Start()
    {
         body.centerOfMass = new Vector2(massOffset, body.position.y);

        _firstFrame = true;
        _followArc = true;
        Destroy(this.gameObject, 10.0f); // destroy in 4 seconds
        destroyTimer = 0; // for off-screen countdown
    }

   
    private void FixedUpdate()
    {
       
        if (_followArc && !_firstFrame)
        {

 // follow an arc
            float angle = Mathf.Atan2(body.velocity.y, body.velocity.x) * Mathf.Rad2Deg;
            transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
        }
        _firstFrame = false;

        if (transform.position.y < -5.25f)
        {
            // Destroy(gameObject);
        }

        // If arrow is out of sight for destroyTimeSet frames, destroy it
        if (!GetComponent<Renderer>().isVisible)
        {
            destroyTimer = destroyTimer + 1;

            if (destroyTimer == destroyTimeSet)
            {
                Destroy(gameObject);
            }
            else
            {
                destroyTimer = 0;
            }
        }
    }


    public void OnCollisionEnter2D(Collision2D collision)
    {
        _followArc = false; // switches off arcing when it hits something
                         
        body.velocity = Vector3.zero;
        body.angularVelocity = 0;
        body.isKinematic = true;
        transform.parent = collision.transform; // Makes the arrow a child of the object it hits

         arrowCollider.enabled = !arrowCollider.enabled; // Disable colliders


  }
}

I mostly followed a tutorial on this, so I don’t know where the issue has arisen.

Change the collision mode on the Rigidbody to be continuous.

I also notice this possible issue:

With Physics (or Physics2D), never manipulate the Transform directly. If you manipulate the Transform directly, you are bypassing the physics system and you can reasonably expect glitching and missed collisions and other physics mayhem.

Always use the .MovePosition() (you are letting physics move itself so this does not apply to you!) and .MoveRotation() (this does apply to you above) methods on the Rigidbody (or Rigidbody2D) instance in order to move or rotate things. Doing this keeps the physics system informed about what is going on.

https://discussions.unity.com/t/866410/5

https://discussions.unity.com/t/878046/8

1 Like

Amazing! Much improved for those changes, thank you :slight_smile:

1 Like