Vector3.MoveTowards not working with collisions?

Viewed 620

I am trying to make smooth plane movement that follows the cursor.

This is the code that does so:

void Update()
    {
        Vector3 mousePos = Input.mousePosition;
        mousePos.z = 0;
        Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);

        mousePos.x = mousePos.x - objectPos.x;
        mousePos.y = mousePos.y - objectPos.y;

        float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle + rotationOffset));

        Vector3 targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        targetPos.z = 0;
        transform.position = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);

        if (transform.position == targetPos)
        {
            Die();
        }
    }
    public void OnCollisionEnter2D(Collision2D col)
    {
        Debug.Log("hit");
    }

This works well by its self but I have run into an issue where it doesn't detect collision. Ive never used Vector3.MoveTowards with movement before but I'm guessing that's the problem. If anyone had any suggestions it would be very appreciated.

2 Answers

Relating to Armin's comment, transform.position==targetPos will virtually never return true. That is just because of the large amount of precision in floats and inherent problems with floating point comparison.

A simple solution would be to check if the distance is within some delta. I recommend using square magnitude of distance for performance reasons. Example:

const float squareCollisionDistance = 4f;//actual collision distance will be 2
var offsetVector = targetPos-transform.position;
var squareDistance = offsetVector.sqrMagnitude;
if (squareDistance < squareCollisionDistance)
    {
        Die();
    }

Something else to look into is RigidBodies I think they have a collision event that you can listen to. Collision detection can be really tricky business and it is worthwhile to use Unity's built in features when you can.

Please read Colliders -> Collision Action Matrix

  • At least one of your objects needs to have a Rigidbody2D component
  • both need to have a 2D collider.
  • both need to be non-triggers

But that's not all: As soon as you use physics you do not want to move your objects via Transform in Update since this overules the physics and thereby breaks collision detection.

rather use e.g. Rigidbody2D.MovePosition and Rigidbody2D.MoveRotation within FixedUpdate

[SerializeField] private Rigidbody2D rigidbody;

private void Awake ()
{
    if(! rigidbody) rigidbody = GetComponent<Rigidbody2D>();
}

void FixedUpdate()
{
    var mousePosScreen = Input.mousePosition;
    var objectPosScreen = Camera.main.WorldToScreenPoint(rigidbody.position);

    var delta = mousePosScreen - objectPosScreen;
    var angle = Mathf.Atan2(delta.y, delta.x) * Mathf.Rad2Deg;
    var targetRotation = angle + rotationOffset;

    var mousePosWorld = Camera.main.ScreenToWorldPoint(mousePosScreen);
    var targetPosWorld = Vector2.MoveTowards(rigidbody.position, mousePosWorld, speed * Time.deltaTime);

    rigidbody.MoveRotation(targetRotation);
    rigidbody.MovePosition(targetPosition);

    if (rigidbody.position == targetPosWorld)
    {
        Die();
    }
}

public void OnCollisionEnter2D(Collision2D col)
{
    Debug.Log("hit");
}
Related