0
\$\begingroup\$

I have 2d grid in a 3d world facing the world up. My camera is setup so it shows an isometric view of the grid.

I want to get the player's input in screen space (cyan) and find the same point on the grid (purple) ignoring the z position which will ultimately select the nearest tile (red square) from the input. I want to do this without using colliders as there could be hundreds of tiles in the same scene.

I want to know how I can project the screen space point into the 2d grid in a 3d world. The image below summarizes what I want to achieve.

How do I calculate the purple dot?

\$\endgroup\$
  • \$\begingroup\$ Is it safe to assume the axes of your grid are aligned with world x & z, with your camera looking along a 45 degree heading between them? \$\endgroup\$ – DMGregory May 5 at 14:18
  • \$\begingroup\$ Yes that is exactly my set up. My camera rotation is (30, 45, 0) and the bottom-leftmost corner of the grid (A1) is at (0, 0, 0). \$\endgroup\$ – Lance Gray May 5 at 14:20
1
\$\begingroup\$

You can add one collider which covers the whole grid. You can then use a usual mouse-into-scene raycast. The resulting RaycastHit object has a member Vector3 point which is the point in world space where the collider was hit.

Assuming your tiles are in a two-dimensional array, each tile is 1 unit in size and the origin of your tilemap is at world coordinates 0:0, you should be able to do something like this:

 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 RaycastHit hit;
 if (Physics.Raycast(ray, out hit)) {
       // check if we actually hit the tilemap and not something else
       if (hit.collider.gameObject == myTilemap) {
           // convert world coordinates into tilemap coordinates
           // This might get a bit more complicated if the assumptions above do not apply
           int tileX = Mathf.FloorToInt(hit.point.x);
           int tileY = Mathf.FloorToInt(hit.point.z);
           Tile hitTile = tilemap[tileX][tileY];

           /* process hitTile */
       }
 }
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You can even do this without a collider using the Plane data structure \$\endgroup\$ – DMGregory May 5 at 15:07
  • \$\begingroup\$ @DMGregory That's also an interesting solution. But I would still prefer to use a collider because that way you get a visualization of the clickable plane in the scene editor and can also easily extend the code to use the same raycast to detect clicks on clickable objects on the grid. \$\endgroup\$ – Philipp May 5 at 15:14
  • \$\begingroup\$ @Philipp Thanks for the answer. I didn't know you can use one collider for the entire grid. But DMGregory's comment is closer to what I want (no collider usage) but with way less mathematics. \$\endgroup\$ – Lance Gray May 6 at 3:55
  • \$\begingroup\$ @DMGregory Can you post that as an answer so I can mark it answered? \$\endgroup\$ – Lance Gray May 6 at 3:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.