- Home /
The question is answered, right answer was accepted
Drag Object Script Problem
So i was making a script that would allow me to click and drag a rigidbody with the mouse, and for the most part it was working, but a minute problem i had with it was that that when i clicked on it the object snapped to my cursor, because in the script it just goes to the mouse position, but i wanted it to drag it around by the point on the object it clicked. I was hoping somebody could help by telling me how i could do that. Feel free to ask about anything you don't understand. Thank You.
My script:
public class Drag : MonoBehaviour {
float d;
public Rigidbody2D rigid;
public bool held;
void Update (){
d = Input.GetAxis("Mouse ScrollWheel");
if(held == true && d > 0f){
transform.Rotate(Vector3.forward * d * 7);
}else if(held == true && d < 0f){
transform.Rotate(Vector3.forward / d / 7);
}
}
void OnMouseDrag (){
Vector2 mousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
Vector2 objPosition = Camera.main.ScreenToWorldPoint(mousePosition);
transform.position = objPosition;
rigid.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY;
held = true;
}
void OnMouseUp(){
rigid.constraints = RigidbodyConstraints2D.None;
}
}
Answer by wibble82 · Dec 22, 2015 at 01:00 PM
Probably the simplest way to achieve something along these lines would be:
When the mouse is first clicked, calculate a 3D position the user clicked on in world space (presumably at z=0, as that's what you're current assuming here by converting ScreenToWorldPoint to a 2D vector
Use transform.InverseTransformPoint to get the 'local space' position that corresponds to, and store it
Each frame while dragging, convert the stored 'local space' position back to world space using transform.TransformPoint
Calculate the difference between the current mouse position and that new position
Add the difference to transform.position
What we're effectively doing with that process is storing 'where on the object' the user originally clicked. Then each frame we're taking that point on the object, and working out 'where it is now'. Finally, we're comparing that position to the current mouse position and working out the error, which we're correcting by changing the position of the object.
Very roughly, it'd look like this:
public class Drag : MonoBehaviour
{
float d;
public Rigidbody2D rigid;
public bool held; //stores whether currently holding the object
Vector3 localHeldPosition; //stores where we grabbed it
void Update ()
{
d = Input.GetAxis("Mouse ScrollWheel");
if(held == true && d > 0f){
transform.Rotate(Vector3.forward * d * 7);
}else if(held == true && d < 0f){
transform.Rotate(Vector3.forward / d / 7);
}
}
void OnMouseDrag ()
{
//get mouse position
Vector2 screenMousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//convert to world space (on z=0 plane)
Vector3 worldMousePosition = Camera.main.ScreenToWorldPoint(screenMousePosition);
worldMousePosition.z = 0; //this is to make sure the position stays on the z=0 plane
//if weren't holding last frame, remember where we grabbed it in local space
if(!held)
{
localHeldPosition = transform.InverseTransformPoint(worldMousePosition);
held = true;
}
//calculate the current position of the grabbed point in world space
Vector3 worldHeldPosition = transform.TransformPoint(localHeldPosition);
//calculate the 'error' - i.e. how much we need to move that point to fix things
Vector3 worldDelta = worldMousePosition-worldHeldPosition;
//fix it just by moving out object
transform.position += worldDelta;
rigid.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY;
held = true;
}
void OnMouseUp()
{
rigid.constraints = RigidbodyConstraints2D.None;
held = false;
}
}
But there's definitely work to do:
I'm not sure how your scene is setup, but unless you're using an orthographc camera and all your objects are on the z=0 plain, there's likely to be issues with conversion from screen to world space
Moving rigid bodies by directly setting the transform.position isn't good - you should look into how to correctly move rigid bodies around (look up MovePosition)
This will move the object, but won't give an actual 'drag' effect - the object won't rotate towards the cursor. If you want that behaviour you'll need to look into point forces.
Hope that helps get you started :)
-Chris
Thank you so much this works great.
To clarify how my scene is currently working, i am using orthographic camera because my prototype thing is 2D, i basically just want to make some 2D physics environment for fun :D.
I will look into a better way of moving my object around, i just started on this today so i wanted to get some sort of fun mechanic working to keep me interested.
Thank You. :D
Answer by Ronin Davis · Dec 22, 2015 at 02:14 PM
I figured out the best way to move the object for anyone who stumbles upon this thread wondering how to do this.
So here's the script i ended up with:
float d;
public Rigidbody2D rigid;
public bool held; //stores whether currently holding the object
Vector3 localHeldPosition; //stores where we grabbed it
void Update ()
{
d = Input.GetAxis("Mouse ScrollWheel");
if(held == true && d > 0f){
transform.Rotate(Vector3.forward * d * 7);
}else if(held == true && d < 0f){
transform.Rotate(Vector3.forward / d / 7);
}
}
void OnMouseDrag ()
{
//get mouse position
Vector2 screenMousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//convert to world space (on z=0 plane)
Vector3 worldMousePosition = Camera.main.ScreenToWorldPoint(screenMousePosition);
worldMousePosition.z = 0; //this is to make sure the position stays on the z=0 plane
//if weren't holding last frame, remember where we grabbed it in local space
if(!held)
{
localHeldPosition = transform.InverseTransformPoint(worldMousePosition);
held = true;
}
//calculate the current position of the grabbed point in world space
Vector3 worldHeldPosition = transform.TransformPoint(localHeldPosition);
//calculate the 'error' - i.e. how much we need to move that point to fix things
Vector3 worldDelta = worldMousePosition-worldHeldPosition;
//fix it just by moving out object
rigid.MovePosition(transform.position + worldDelta);
held = true;
}
void OnMouseUp()
{
rigid.constraints = RigidbodyConstraints2D.None;
held = false;
}