# How do I get mouse x / y of the world plane in Unity?

I am trying to make a tiled landscape. The terrain itself is not made from tiles but the world has a grid which I define.

I would like to place boxes/rectangles which snap to this grid, at runtime, but in order for me to do that I must get a projection from the user screen to the real-world coordinates.

I have tried various examples using the Ray class but nothing worked. It compiles and outputs a constant value no matter where I put the mouse. I have tried to add some tiles and try to detect them but no luck. I also tried with one plane as big as my world but still no luck.

I am using C# but even a JS version would be helpful.

This technique involves calculating which tile the mouse is under by the x and y positions. Perhaps detecting which tile itself is being pointed to would be a simpler task, at which point I can just retrieve its i/j properties.

• This is hard to help since we don't really know what you have tried. I have done similar things quite sometimes. Have you tried Camera.ScreenPointToRay? – nathan May 26 '14 at 7:42
• Yes. I have Googled all weekend and tried all the snippets of code I could get my hands on, most from stackexchange. Nothing worked, just got a constant Vector3. I assume I am the one doing (or not doing) something. But I don't know what I don't know :| – Discipol May 26 '14 at 7:56
• Could you try to create a minimal project as a test case and submit the relevant code snippet here? – nathan May 26 '14 at 8:12
• One of the important things for raycasting in Unity is that the target MUST have a collider attached. Try adding a collider to the tiles and see if that works. – PixelArtDragon May 26 '14 at 8:53
• I will try your suggestion Garan then post the project, nathan, once I get home from work :D – Discipol May 26 '14 at 9:16

Instead of using a collider for your terrain, you can also use a plane to perform a raycast. For example, if your grid is situated on the XZ plane, you can do something like this:

static Plane XZPlane = new Plane(Vector3.up, Vector3.zero);

public static Vector3 GetMousePositionOnXZPlane() {
float distance;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(XZPlane.Raycast (ray, out distance)) {
Vector3 hitPoint = ray.GetPoint(distance);
//Just double check to ensure the y position is exactly zero
hitPoint.y = 0;
return hitPoint;
}
return Vector3.zero;
}


This will return a 3D world position of where the mouse intersects with the XZ plane. You can then round the x and z values to the nearest integer value to have a snapping effect when placing your objects. Similar to how Bummzack does in his code:

position.x = Mathf.Round(position.x / GridSize) * GridSize;
position.z = Mathf.Round(position.z / GridSize) * GridSize;


Using the plane method ensures you don't have to change the size or position of your terrain collider when moving around your world.

• +1. Neat, I've never used Plane before. In case of a flat world/grid that covers the entire screen this is the better approach. – bummzack May 26 '14 at 13:30

First of all, you need to attach a collider to your terrain in order to get hits from raycasts. If you're using a Terrain, it should already have a Terrain Collider attached to it.

In your script you can then do something like this:

// create a ray from your mouse-position
Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(r, out hit)){
// if the ray hit a collider, we'll get the world-coordinate here.
Vector3 worldPos = hit.point;

// round coordinates to grid-size (GridSize could be a constant or a
// public class member that you can change in the Inspector).
worldPos.x = Mathf.Round(worldPos.x / GridSize) * GridSize;
worldPos.z = Mathf.Round(worldPos.z / GridSize) * GridSize;
// you can do the same for the y-coordinate, if you need grid
// snapping in the y-axis.

// position your object at the calculated position:
MyObject.transform.position = worldPos;
}


From your question I assumed that your grid only applies to the X & Z axes. Of course you could also apply it to the Y axis or leave the Y coordinate untouched (which will position the object at the Y position of the ray/terrain intersection). If you have a terrain with elevation, this might not lead to the desired results and you'll have to cast another ray downwards at the new position (eg. the one that lies on your X/Z grid) to get the exact Y-coordinate.