Search code examples
c#unity-game-enginegame-physics

Unity 3D OnMouseDrag collision


I am trying to make a game where you drag different types of spheres and put them together to form a figure (without any gravity). For dragging the objects I use this script:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {

    void OnMouseDrag()
    {
        float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
        transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen ));

    }

}

When I drag two spheres to eachother they go trough eachother. I added a rigibody to the objects, tried a LOT of different things with it, but nothing seemed to work. They always seem to bounce off eachother OR they just don't collide at all. Any sollution to this? Imagine this like a person running in to a wall. The person doesn't bounce off the wall, he just stops moving.


Solution

  • The reason why you're getting some strange behaviour (objects clipping through/ignoring each other) is that you're setting transform.position directly, rather than manipulating the Rigidbody component of the object. Use Rigidbody.MovePosition() to also take into account physics when positioning an object.

    Now, seeing objects bounce off each other is not an abnormal physics behaviour - this is because when objects clip into each other (as they will often do with your code), they exert a repulsing force on each other (a bit like Newton's third law). If you want to freeze them as soon as they collide, try setting Rigidbody.isKinematic = true in the OnCollisionEnter() event.

    Bringing this all together, your class might look like:

    public class Test : MonoBehaviour {
    
        Rigidbody rb;
    
        void Start()
        {
            // Store reference to attached Rigidbody
            rb = GetComponent<Rigidbody>();
        }
    
        void OnMouseDrag()
        {
            float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
    
            // Move by Rigidbody rather than transform directly
            rb.MovePosition(Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen )));
        }
    
        void OnCollisionEnter(Collision col)
        {
            // Freeze on collision
            rb.isKinematic = true;
        }
    }
    

    Hope this helps! Let me know if you have any questions.