- Home /
Have a gameObject follow the mouse in sync. So that the mouse pointer is always over the object. Even as the camera is rotated.
Hi,
So a couple weeks ago I asked a similar question here : http://answers.unity3d.com/questions/10268/have-a-gameobject-follow-the-mouse-in-sync-so-that-the-mouse-pointer-is-always-o
Today, I realized the solution to the problem wasn't so straightforward.
What I want is to be able to drag a cube around with the mouse, in a way that syncs perfectly with the mouse. The mouse cursor should always remain over the object, and visually, the object should move as much as the mouse did. This should work no matter what the rotation angle of the camera is. The cube should also be exactly under the point where we clicked, it shouldn't snap to its center.
Here is what I have that works, when the camera is looking perfectly perpendicular to the Z axis, but breaks when the camera is rotated or moved around at different angle:
private Vector2 snapOffset;
void OnMouseDown() { Vector3 temp = Camera.mainCamera.WorldToScreenPoint(transform.position);
snapOffset = new Vector2(Input.mousePosition.x - temp.x, Input.mousePosition.y - temp.y);
Debug.Log("snap offset: " + snapOffset);
}
void OnMouseDrag() { Vector3 mousePosition = new Vector3(Input.mousePosition.x - snapOffset.x, Input.mousePosition.y - snapOffset.y, 0); mousePosition.z = transform.position.z - Camera.mainCamera.transform.position.z;
Debug.Log("mousePosition: " + mousePosition);
transform.position = Camera.mainCamera.ScreenToWorldPoint(mousePosition);
}
This code works, if the camera is pointing straight at the cube from in front. If you rotate the camera, say 45 degrees, it will stop working.
I want a solution that does not use Ray-casting.
Thank you.
Answer by skovacs1 · Jul 07, 2010 at 10:58 PM
I think your question could use come clarification as to how you are moving your camera, but I think I get your meaning.
Have you considered something like:
Vector3 screenPosition;
//Store the screen position of the object when the mouse clicks void OnMouseDown() { screenPosition = Camera.mainCamera.WorldToScreenPoint(transform.position); }
//When the mouse drags, change the object's screen position accordingly. void OnMouseDrag() { //Read the mouse input axes screenPosition.x += Input.GetAxis("Mouse X"); screenPosition.y += Input.GetAxis("Mouse Y");
//move the object to the world position to not change screen position
transform.position = Camera.mainCamera.ScreenToWorldPoint(screenPosition);
}
This way the object is not centred to the mouse, but will keep its relative position on screen to where the mouse was clicked.
If the camera rotates in this script, then you can easily check if the mouse is held down and call transform.position = Camera.mainCamera.ScreenToWorldPoint(screenPosition); when the camera rotates
If the camera rotates in a separate script (which it likely does), I suggest making the relevant data public to the camera rotation so that it can update the object's transform if applicable (the mouse is still down). The exposed data could be the selected object and its stored screen position or a public function like updatePosition which will make the call to set the transform and then your rotate function and mousedrag can both call this.
Answer by Tetrad · Jul 07, 2010 at 05:56 PM
Try using something like Camera.ScreenPointToRay
.
So i.e.
Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );
transform.position = ray.GetPoint( distanceFromScreen );
Where distanceFromScreen is a fixed distance from the screen.
You'll have to use raycasting if you want to make sure your object doesn't go "behind" something, though. So you'd cast a ray, do a trace, and put your object's position at either what I had before, or the hit.point, whichever is closer.
Not sure what you mean by "going behind". Your method does work, but it snaps to the middle of the cube. Also, how do I find the distanceFromScreen? Doing the difference of the z position does not work when the camera is rotated say 45 degrees on the Y axis.
With that method, distanceFromScreen is just a "place this at this distance from the screen". If you want it to be a fixed amount you could get the magintude from the camera transform to the game object transform. i.e. (Camera.main.transform.position - transform.position).magnitude
Ya, I'd like my cube to be at the same distance it was from the camera as before, but finding the distance from the camera to the cube is behaving strangely. It's giving me 2 issues. The first one is, every time I click on the cube, it gets a little farther away from the camera. The second one is, it seems to be moving in a kind of arc, as you get to the edge of the screen, the cube gets closer to the camera, and when you are close to the middle, it gets farther.
Well that's how camera's work. It's technically the same distance, just not on the same plane.
If I move my mouse x amount to the left, the cube should move x unit to the left, while visually staying at the same distance from the camera. Say I move the mouse 10 pixel on the X axis. I first need to convert that in world unit. I can do this with ScreenToWorldPoint I think. This means that 10 pixel on the screen space is equivalent to lets say 100 unit in world space. So I then move the cube 100 unit on the X axis. But the problem is that when the camera is rotated. The world X axis is not parallel with the camera anymore. So I need a way to move 100 unit paralel with the camera clip plane