Search Unity

2D Physics Moving an Object with the Mouse

Discussion in 'Physics' started by whitesmoque, Jun 12, 2019.

  1. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Hi, right now I am trying to make a script that moves an object with the mouse, specifically a paddle. The script I have keeps the object on a specific y value, while matching the x value of the mouse.

    Code (CSharp):
    1.  
    2. {
    3.  
    4.    [SerializeField] private float screenWidthInUnits = 18f;
    5.  
    6.      // Use this for initialization
    7.    void Start () {
    8.      
    9.    }
    10.    
    11.    // Update is called once per frame
    12.    void Update ()
    13.    {
    14.       float mousePosInUnits = Input.mousePosition.x / Screen.width * screenWidthInUnits;
    15.       Vector2 paddlePos = new Vector2(mousePosInUnits   , transform.position.y);
    16.       transform.position = paddlePos;
    17.    }
    18.      
    19.    
    20.    
    21. }
    22.  
    However the problem arises when I move the mouse too fast to hit the ball, it passes directly over top of the ball and causes the ball's velocity to become zero. I believe that the problem is that the paddle has no velocity and it is just moving to a direct position.

    How would I make a script that would allow the paddle to follow the mouse, without too much delay, but also with enough friction that it would not go over an object immediately?

    Thanks.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,456
    Try using the TargetJoint2D. You can see it being used for all drag operations in the 2D physics test repo here as well as this specific test scene here. Whilst there it's used for mouse-dragging and is set to be quite soft, you can make it a rigid joint. It moves because the joint applies impulse forces to meet the target position you (continually) set. It therefore moves with velocity and honours things like continous col-det and interpolation.
     
    whitesmoque likes this.
  3. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Hey thanks, this is indeed what I was looking for, also you have a new subscriber ;)

    This is the script that I attached to my paddle.

    Code (CSharp):
    1.  
    2. public class EternalFolloScripy : MonoBehaviour
    3. {
    4.     public TargetJoint2D TJ2D;
    5.  
    6.     public bool m_DrawDragLine = true;
    7.     public Color m_Color = Color.cyan;
    8.     // Start is called before the first frame update
    9.     void Start()
    10.     {
    11.         TJ2D = GetComponent<TargetJoint2D>();
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         var worldPos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    18.        
    19.         TJ2D.target = TJ2D.transform.InverseTransformPoint(worldPos);
    20.        
    21.        
    22.         if (TJ2D)
    23.         {
    24.             TJ2D.target = (worldPos);
    25.  
    26.          
    27.             if (m_DrawDragLine)
    28.                 Debug.DrawLine (TJ2D.transform.TransformPoint (TJ2D.anchor), worldPos, m_Color);
    29.         }
    30.  
    31.  
    32.     }
    33. }
    34.  
    35.  
    However when I try to disable movement on the y axis:
    Code (CSharp):
    1.  
    2. var worldPos = Camera.main.ScreenToWorldPoint (Input.mousePosition.x, transform.position.y);
    3.  
    I am met with the error : "Argument type ‘float’ is not assignable to parameter type ‘UnityEngine.Vector3’"

    How would I constrain the movement on the y while allowing free movement on the x?
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,456
    As the error states, you're passing two floats to a method which the docs state require a Vector3. Unity will automatically convert a Vector2 to a Vector3 for you so you can simply pass in "Input.MousePosition" like here. Note that this script is the one that's used to generically drag draggable items.

    You can either set the Y-axis constraint on the Rigidbody2D or add a SliderJoint2D and set the angle to 0 or 180.
     
    Last edited: Jun 13, 2019
    whitesmoque likes this.
  5. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Thanks so much! I am new to unity so it really helps. :D
     
    MelvMay likes this.
  6. indie6

    indie6

    Joined:
    Dec 15, 2012
    Posts:
    101
    Hi, sorry for bringing up this old thread. I have one question, the joints target is being moved in Update(), shouldn't it move specifically in FixedUpdate() so it's in sync with physics?

    This piece of code
    Code (CSharp):
    1.  
    2.         // Update the joint target.
    3.         if (m_TargetJoint)
    4.         {
    5.             m_TargetJoint.target = worldPos;
    6.  
    7.             // Draw the line between the target and the joint anchor.
    8.             if (m_DrawDragLine)
    9.                 Debug.DrawLine(m_TargetJoint.transform.TransformPoint(m_TargetJoint.anchor), worldPos, m_Color);
    10.         }
    11.  
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,456
    Preferably yes but it won't stop it working. You'll just potentially ask for a position multiple times before the simulation actually runs and does something with it so it's just wasted effort.

    This is the same for anything physics, not this joint and this setting.

    If you've set the physics to run per-frame then this is how you'd do it so it's not a hard rule.
     
    indie6 likes this.
  8. indie6

    indie6

    Joined:
    Dec 15, 2012
    Posts:
    101
    Thank you for the answer!