0
\$\begingroup\$

I have a game that uses a tile map, and I'd like to draw numbers representing positions on the tile map while playing the game. This would, for example, let me easily write down a note that I want to make changes at a specific coordinate.

I've written a script which grabs the Tilemap object and assigns it to a variable called m_map, and then:

void OnGUI()
{
    for (int x = -15; x < 15; ++x)
    {
        for (int y = -15; y < 15; ++y)
        {
            //if (GetTile(x, y) == null) continue;

            if (Camera.main != null)
            {
                Vector3 coord = m_map.GetCellCenterWorld(new Vector3Int(x, y, 0));

                Vector3 screenCoord = Camera.main.WorldToScreenPoint(coord);

                GUI.Label(new Rect(screenCoord.x, screenCoord.y, 200, 200), string.Format("{0},{1}", x, y));
            }
        }
    }
}

However, this does not produce the results I would expect. The Y-axis is inverted, for example, and X-axis seems to be off by a cell or two. Moving the camera along the Y-axis also causes the labels to move away from the tiles they are supposedly numbering, which means it definitely isn't correct.

It seems I must have made some bad assumption about one of these coordinate systems, but I can't figure out what.

\$\endgroup\$
3
  • \$\begingroup\$ What type of object is m_map? It seems that GetCellCenterWorld's implementation is incorrect. \$\endgroup\$
    – nihohit
    Mar 27 '19 at 9:21
  • \$\begingroup\$ @nihohit It is the built-in Tilemap class: docs.unity3d.com/Manual/class-Tilemap.html . This class also has a method CellToWorld, which gives me similar results (the labels are positioned in a different part of the cell, but that's the expected difference between the two). \$\endgroup\$ Mar 27 '19 at 13:57
  • \$\begingroup\$ Applyguysnake's solution solves the problem, but for anyone else trying to use GUI.Label, the answer is that GUI space is not the same coordinate system as screen space -- it is negated in Y, so screenSpaceY = Screen.height - guiSpaceY. Why did Unity need a fourth coordinate system? No idea. The horizontal offset I thought I had was just from text size and became obvious once I got the vertical corrected. \$\endgroup\$ Mar 28 '19 at 3:36
1
\$\begingroup\$

If I remember correctly, the tile coordinates are based on the lower-left corner of the tile, so if you called this method on (1,1) you might expect that to be within tile (0,0) but it's the next one up and over. That may be accounting for some of your coordinates being off. More importantly, your loop is creating a Vector3 starting at (-15,-15) but that's relative to the world, not the camera's position. So if the camera is at (40,40) you're trying to line up coordinates with tiles that are offscreen. Also keep in mind how many tiles are on screen and the spacing of the labels will change with the zoom level so you'd want to orient your labels in world space, not in relation to the camera.

(Minor note while we're here, Camera.main is just a shortcut for FindGameObjectsWithTag, and you're doing that 900 times per frame, which is very slow considering there shouldn't be a reason for the camera to become null mid-loop.)

I'm not 100% clear on what your goal is. Are you just trying to get references for development? Or are you trying to have the tile coordinates display in the game, on the tiles?

If you're just looking for references during development, try this:

Vector3 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
SomeMethod(m_grid.WorldToCell(worldPoint));

SomeMethod can just update a text box on screen so you have a constant display of what cell your cursor is on, or you can have it save the cell when you click, or whatever you like.

From there the answer will depend on exactly what you want to do and how you want it to look, but here's a place to start. This will give you the coordinates of the bottom-left and top-right tiles on screen, regardless of camera size or position:

bottomLeft = _grid.WorldToCell(mainCamera.ViewportToWorldPoint(new Vector3(0, 0, 0))),
topRight = _grid.WorldToCell(mainCamera.ViewportToWorldPoint(new Vector3(1, 1, 0)))

You could use that to find a start and end point for your loop and your code might work fine as is from there.

If you want the tiles to display their coordinates during the game, or even in development, it would probably be possible to create a scriptable tile that displays coordinates based on where it is and have those on a separate tilemap underneath or over your main tilemap. Although I'm not sure how you'd render text to a tile. Your OnGUI method should be perfectly fine to start though.

\$\endgroup\$
4
  • \$\begingroup\$ Hey, thanks for the help. I apologize, I should have been more clear: I do realize the limitations of the constant numbers, and that this means if the camera moves too far away from the origin, it obviously won't work. I was trying to keep the example simple stupid but I guess I made it distracting. You mouse position example works great and accomplishes what I need; it gives me the results I expect. The only difference is that I was hoping to put the labels on the tiles themselves rather than in the corner. Since your method works, I must have a bad assumption about GUI.Label. \$\endgroup\$ Mar 27 '19 at 14:11
  • \$\begingroup\$ I think you can probably still do something like you were intending with GUI.Label, but I haven't used it so I don't know the best way to go about it. It probably would just involve more steps converting world points to screen points. \$\endgroup\$ Mar 27 '19 at 23:46
  • 1
    \$\begingroup\$ Finally found the right search phrase and found the following in some Unity forums. "GUI space" is NOT screen space. I'm accepting this as the answer since it does accomplish the goal, but wanted to put this for posterity. "Before OnGUI showed up in Unity 2, there was only screen space, viewport space, and world space. OnGUI added GUI space, which is like screen space, but top-down rather than bottom up" "If you're talking about the fact that the y axis goes in opposite directions in screen space and GUI space, that's just the way it is - you'll just have to deal with it" \$\endgroup\$ Mar 28 '19 at 3:33
  • \$\begingroup\$ That's very weird, and good to know! \$\endgroup\$ Mar 28 '19 at 3:37

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.