4
\$\begingroup\$

Right now it is quite hard in Unity 2017.2 to track where is the (0, 0) coordinate in the tilemap editor, when painting. I tend to use a displayable dummy game object as a marker.

I'd like to also edit two different sets of tilemaps. One set* of tilemaps is located at (0, 0, 0) absolute position, and another set of tilemaps in, say, (32, 0, 0) position. However it is quite confusing to me (perhaps there is an option, but I can't find it) when trying to guess where is the internal center of the currently focused tilemap, to start painting. If somehow I had to paint several different tilemaps (more than two sets, say), I'd get easily dazed by the tool.

(* A set of tilemaps is not any kind of special objects, but just a concept embracing several tilemaps in the same position).

Question: Does Unity provide a way in the editor/UI to know the place of the (0, 0) coordinate inside the tilemap (when editing and focusing a specific tilemap)?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Maybe you could solve the problem by attaching an editor script to the tilemap which draws a gizmo? I'll try to do something later when I am at home. \$\endgroup\$
    – Philipp
    Commented Aug 10, 2018 at 11:14

5 Answers 5

7
\$\begingroup\$

The select tool.
Clicking any tile with the select tool, the inspector will tell you the position relative to 0,0.

With a little bit of math (and/or additional clicks), you can hone in on whichever tile you are searching for

https://docs.unity3d.com/Manual/Tilemap-Painting.html

select tool -- inspector

\$\endgroup\$
3
\$\begingroup\$

It is an old question - There doesn't still seem to be easy way to show clearly the origin and the bounds of a Tilemap, but it can be solved with a script that runs in the Editor like Philipp said.

I created this script. Red border shows the Tilemap current bounds, green cross shows the 0,0,0 position of Tilemap. Script does take into account position of Tilemap in World space, but if the Grid or Tilemap is scaled or rotated the rendering no longer will be aligned to Tilemap. It is also possible to see the unused space where user has erased the tiles, but hasn't compressed the bounds:

enter image description here

I might extend this and put it to my GitHub, but here is the current version.

Add the script to any Tilemap for which you want to show bounds + origin, and the code will run in Editor automatically.

using UnityEngine;
using UnityEngine.Tilemaps;

public class DrawTilemapBorder : MonoBehaviour
{
    Tilemap tilemap;

    void OnValidate()
    {
        if (tilemap == null)
            tilemap = GetComponent<Tilemap>();
    }

    void OnDrawGizmos()
    {
        Draw();
    }

    void Draw()
    {
        if (tilemap == null)
            return;

        // tilemap position
        var tp = tilemap.transform.position;

        // bounds + offset
        var tBounds = tilemap.cellBounds;

        // corner points
        var c0 = new Vector3(tBounds.min.x, tBounds.min.y) + tp;
        var c1 = new Vector3(tBounds.min.x, tBounds.max.y) + tp;
        var c2 = new Vector3(tBounds.max.x, tBounds.max.y) + tp;
        var c3 = new Vector3(tBounds.max.x, tBounds.min.y) + tp;

        // draw borders
        Debug.DrawLine(c0, c1, Color.red);
        Debug.DrawLine(c1, c2, Color.red);
        Debug.DrawLine(c2, c3, Color.red);
        Debug.DrawLine(c3, c0, Color.red);

        // draw origin cross
        Debug.DrawLine(new Vector3(tp.x, tBounds.min.y + tp.y), new Vector3(tp.x, tBounds.max.y + tp.y), Color.green);
        Debug.DrawLine(new Vector3(tBounds.min.x + tp.x, tp.y), new Vector3(tBounds.max.x + tp.x, tp.y), Color.green);
    }
}
\$\endgroup\$
1
\$\begingroup\$

This may be counterintuitive as one would expect the focused tilemap in the palette reveals its zero/origin. However that doesn't happen. Instead, to find the zero you will not only focus the tilemap in the palette, but also focus the tilemap in the game hierarchy.

The latter will reveal the little blue ring of its origin in terms of game space. You will notice the ring is in the corner of 4 squares (tiles), being the left-top one the square being (0, 0) and your coordinates system growing up-right. However as a guideline ensure you paint the (0, 0) tile at the end (or any of the four tiles in contact with the little blue ring marking the position), because the painted tiles will hide it. Unfortunately Unity does not have an additional way to marking the origin.

\$\endgroup\$
0
1
\$\begingroup\$

You can use this gizmo. It looks like this. More info in this tweet. Basically, what it does is draw the axes' cordinates of a selected Grid or Tilemap component. When zoomed in enough it draws the coordinates inside each tile, instead of axes, to ease visualization.

this

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Tilemaps;

namespace Utils.Editor.Gizmos
{
    public static class GridCoordinatesGizmo
    {
        [DrawGizmo(GizmoType.Selected)]
        public static void DrawGizmo(Grid grid, GizmoType gizmoType)
        {
            Draw(SceneView.currentDrawingSceneView, grid);
        }
        
        [DrawGizmo(GizmoType.Selected)]
        public static void DrawGizmo(Tilemap tilemap, GizmoType gizmoType)
        {
            Draw(SceneView.currentDrawingSceneView, tilemap.layoutGrid);
        }
        
        private static void Draw(SceneView sceneView, Grid grid)
        {
            var camera = sceneView.camera;
            var bottomLeftWorld = camera.ViewportToWorldPoint(Vector3.zero);
            var topRightWorld = camera.ViewportToWorldPoint(Vector3.one);
            
            var labelStyle = new GUIStyle(GUI.skin.label)
            {
                fontStyle = FontStyle.Bold,
                alignment = TextAnchor.UpperLeft
            };
            var tmpTextSize = labelStyle.CalcSize(new GUIContent("0"));
            float textHeightWorld = GetVerticalScreenToWorldSize(camera, tmpTextSize.y);
            float textHalfHeightWorld = textHeightWorld * 0.5f;
            float offset = textHeightWorld * 2;

            // compute horizontal variables
            int minCellX = grid.WorldToCell(bottomLeftWorld).x;
            int maxCellX = grid.WorldToCell(topRightWorld).x;
            float minCellXTextSize = GetTextWidthWorld($"{minCellX}", labelStyle, camera);
            float maxCellXTextSize = GetTextWidthWorld($"{maxCellX}", labelStyle, camera);
            float maxWidthSize = Mathf.Max(minCellXTextSize, maxCellXTextSize);

            IEnumerable<int> xCells;
            if (maxWidthSize >= grid.cellSize.x * 0.8f)
                xCells = MathUtils.SplitNicely(minCellX, maxCellX).Select(x => (int) x);
            else
                xCells = Enumerable.Range(minCellX, maxCellX - minCellX + 1);
            
            // compute vertical variables
            int minCellY = grid.WorldToCell(bottomLeftWorld).y;
            int maxCellY = grid.WorldToCell(topRightWorld).y;
            IEnumerable<int> yCells;
            if (textHeightWorld >= grid.cellSize.y * 0.8f)
                yCells = MathUtils.SplitNicely(minCellY, maxCellY).Select(y => (int) y);
            else
                yCells = Enumerable.Range(minCellY, maxCellY - minCellY + 1);

            var xCellsList = xCells.ToList();
            var yCellsList = yCells.ToList();

            string cellText = "XXX ; XXX";
            if (GetTextWidthWorld(cellText, GUI.skin.label, camera) > grid.cellSize.x * 0.7f)
                DrawInAxis(grid, xCellsList, labelStyle, camera, bottomLeftWorld, offset, yCellsList, textHalfHeightWorld);
            else
                DrawInCells(grid, xCellsList, yCellsList, textHeightWorld);
        }

        private static void DrawInAxis(Grid grid, IEnumerable<int> xCells, GUIStyle labelStyle, Camera camera,
            Vector3 bottomLeftWorld, float offset, IEnumerable<int> yCells, float textHalfHeightWorld)
        {
            foreach (var x in xCells)
            {
                string text = $"{x}";
                float textHalfWidthWorld = GetTextWidthWorld(text, labelStyle, camera) * 0.5f;
                
                float xCenter = grid.GetCellCenterWorld(new Vector3Int(x, 0, 0)).x;
                float xText = xCenter - textHalfWidthWorld;
                float yText = bottomLeftWorld.y + offset;
                var handlePos = new Vector3(xText, yText, 0);
                Handles.Label(handlePos, text, labelStyle);
            }

            foreach (var y in yCells)
            {
                string text = $"{y}";
                float yCenter = grid.GetCellCenterWorld(new Vector3Int(0, y, 0)).y;
                float xText = bottomLeftWorld.x + offset;
                float yText = yCenter + textHalfHeightWorld;
                var handlePos = new Vector3(xText, yText, 0);
                Handles.Label(handlePos, text, labelStyle);
            }
        }
        
        private static void DrawInCells(Grid grid, IEnumerable<int> xCells, IEnumerable<int> yCells, float textHeight)
        {
            var xCellsList = xCells.ToList();
            var yCellsList = yCells.ToList();
            foreach (var x in xCellsList)
            {
                foreach (var y in yCellsList)
                {
                    string text = $"{x} ; {y}";
                    var handlePos = grid.CellToWorld(new Vector3Int(x, y, 0));
                    handlePos.y = handlePos.y + textHeight;
                    Handles.Label(handlePos, text, GUI.skin.label);
                }
            }
        }

        private static float GetTextWidthWorld(string text, GUIStyle style, Camera camera)
        {
            var textSize = style.CalcSize(new GUIContent(text));
            float textWidthWorld = GetHorizontalScreenToWorldSize(camera, textSize.x);
            return textWidthWorld;
        }
        
        private static float GetHorizontalScreenToWorldSize(Camera camera, float size)
        {
            float xZeroWorld = camera.ScreenToWorldPoint(Vector3.zero).x;
            float xRightWorld = camera.ScreenToWorldPoint(new Vector3(size, 0, 0)).x;
            return xRightWorld - xZeroWorld;
        }
        
        private static float GetVerticalScreenToWorldSize(Camera camera, float size)
        {
            float yZeroWorld = camera.ScreenToWorldPoint(Vector3.zero).y;
            float yRightWorld = camera.ScreenToWorldPoint(new Vector3(0, size, 0)).y;
            return yRightWorld - yZeroWorld;
        }
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ To prevent link rotting, you may complement your answer with information from the tweets thread you linked. This way, your answer would be still valid even if the link stops working or the tweet gets deleted. \$\endgroup\$
    – liggiorgio
    Commented May 21, 2022 at 17:21
-1
\$\begingroup\$
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class GetTilemapCoordinate : MonoBehaviour
{
    public Grid grid;

    public GetTilemapCoordinate()
    {
        SceneView.duringSceneGui += GetMousePosition;
    }

    public void GetMousePosition(SceneView scene)
    {
        Event e = Event.current;
        if (e != null)
        {
            if (Event.current.type == EventType.MouseDown)
            {

                Vector3Int position = Vector3Int.FloorToInt(HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin);
                Vector3Int cellPos = grid.WorldToCell(position);

                Debug.Log(cellPos);
            }
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to GDSE & thanks for answering! In addition to the code, it would be helpful if you included some commentary explaining how it solves OP's problem. This is especially useful if OP (or others) need to modify the code slightly as it gives them a better understanding of what the code does & why it does it. \$\endgroup\$
    – Pikalek
    Commented Nov 6, 2019 at 17:43

You must log in to answer this question.

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