1
\$\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\$
2
  • \$\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 '20 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 '20 at 14:20
2
\$\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 */
       }
 }
\$\endgroup\$
4
  • \$\begingroup\$ You can even do this without a collider using the Plane data structure \$\endgroup\$
    – DMGregory
    May 5 '20 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 '20 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 '20 at 3:55
  • \$\begingroup\$ @DMGregory Can you post that as an answer so I can mark it answered? \$\endgroup\$
    – Lance Gray
    May 6 '20 at 3:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .