Anchoring HingeJoint2D to clicked upon spot

I'm creating a 2D game where the user can click and drag objects around. This is done by connecting a 'Hand' object to the object the user is current clicking on with a HingeJoint2D. Right now it simply connects the HingeJoint2D to the center of the clicked upon object.

I want to anchor the Hingejoint2D to the exact spot on the rigidbody (not the center) that the user is clicking on. This must involve transforming the clicked upon point to coordinates relative to the clicked upon rigidbody, but I've had no success using methods like transform's TransformPoint.

Any help would be appreciated.

This is the code I have attached to the object that the user will be dragging around:

void OnMouseDown() {
// Create a hinge joint between the hand and this object so object will slowly rotate
// around the hinge point
this.gameObject.AddComponent("HingeJoint2D");
connectingHinge = this.GetComponent<HingeJoint2D>();
connectingHinge.connectedBody = handRigidbody;

// Set anchor to offset of current hand position relative to the object.
//connectingHinge.anchor = new Vector2(offset.x, offset.y);
}

Image of gameplay:

The gray box is the 'hand', which is the mouse cursor. The gun is an object that the user is dragging about while it is connected to the gray box with a HingeJoint2D.

I want to anchor the HingeJoint2D to the exact spot the user is clicking on, and not just the center of the rigidbody.

1 Answer

The anchor in HingeJoint2d is the coordinate in local space where the end point of the joint is attached. In order to transform the coordinates to the gun's local space, you should first subtract the center point of the gun from the world position of the mouse, then inversely rotate it by the gun's rotation, and finally inversely scale this by the gun's scale. This all can be done in one line by calling transform.InverseTransformPoint. ConnectedAnchor works the same way as anchor, but the coordinate has to be given in global space.

public class AddHingeOnClick : MonoBehaviour {
HingeJoint2D hingeJoint2D;

void Start () {
hingeJoint2D = gameObject.AddComponent<HingeJoint2D>();
hingeJoint2D.enabled = false;
}

void OnMouseDown() {
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);

//Vector3 scale = transform.localScale;
//Vector3 inverseScale = new Vector3(1 / scale.x, 1 / scale.y, 1 / scale.z);
//Quaternion inverseRotation = Quaternion.Inverse(transform.rotation);
//Vector3 offset = mouseWorldPosition - transform.position;
//Vector3 mouseLocalPosition = Vector3.Scale(inverseScale, inverseRotation * offset);

Vector3 mouseLocalPosition = transform.InverseTransformPoint(mouseWorldPosition)
hingeJoint2D.enabled = true;
hingeJoint2D.connectedAnchor = mouseWorldPosition;
hingeJoint2D.anchor = mouseLocalPosition;
}
}


I advise against creating the HingeJoint2D in the OnMouseDown() function, there seems to be a bug in Unity 4.6 which prevents it from working.

• Thanks for your thorough and timely response. This is exactly what I was looking for! – DeeCeptor Dec 28 '14 at 7:34
• On a related note, this method does not work when the Transform Scale of the object being clicked on is not 1. Would the mouseLocalPosition need to be multiplied by its scale to get the correct coordinates? – DeeCeptor Dec 28 '14 at 7:49
• You would indeed have to multiply it by the inverse of its scale. I also updated my answer to use transform.InverseTransformPoint. – Dan Dec 28 '14 at 12:13