Ben Traje
← Back to unity

Understanding Unity Grid Movement: Legacy 1D-to-2D Coordinate Math vs Modern Grid Components

10 Sep 26 (1mo ago)

Grid Movement in Unity: Legacy Math vs Modern Tilemaps

When implementing grid-based movement in Unity—common in turn-based strategy, puzzle, or retro top-down games—developers often encounter two approaches: manual 1D-to-2D array math and Unity's native Grid system.

The Legacy Approach: Manual 1D-to-2D Array Math

Before Unity 2017.2, grid systems relied on manual indexing to map flat 1D data arrays into 2D spatial coordinates.

How It Works: State Tracking and Coordinate Mapping

In manual systems, the controller acts as the single source of truth for the object's current position using a state variable (e.g., currentTile).

using UnityEngine;

public class MapMovementController : MonoBehaviour
{
    public Map map;
    public Vector2 tileSize;

    public int currentTile;
    private int tmpIndex;
    private int tmpX;
    private int tmpY;
      
    public void MoveTo(int index)
    {
        currentTile = index;

        PostUtil.CalculatePos(index, map.columns, out tmpX, out tmpY);
        tmpX *= (int)tileSize.x;
        tmpY *= -(int)tileSize.y;

        transform.position = new Vector3(tmpX, tmpY, 0);
    }

    public void MoveInDirection(Vector2 dir)
    {
        PostUtil.CalculatePos(currentTile, map.columns, out tmpX, out tmpY);
        tmpX += (int)dir.x;
        tmpY += (int)dir.y;

        PostUtil.CalculateIndex(tmpX, tmpY, map.columns, out tmpIndex);
        MoveTo(tmpIndex);
    }
}

The Index Conversion Formula

Flat arrays map directly to 2D coordinates through the standard indexing equation:

$$\text{Index} = X + (Y \times \text{Width})$$

public static void CalculateIndex(int x, int y, int width, out int index)
{
    index = x + y * width;
}

  • Deconstruct (1D to 2D): The starting tile index is converted to grid row/column coordinates ($X$, $Y$).
  • Translate: Positional deltas are applied directly to the coordinates ($X + \text{dir.x}$, $Y + \text{dir.y}$).
  • Reconstruct (2D to 1D): The modified coordinates are flattened back into the destination array index and passed to MoveTo().

Common Gotchas with Manual Grid State

  1. Inspector Serialization: Public variables like public int currentTile; serialize within the Unity Editor. If modified in the Inspector, the editor value overrides the field's default declaration upon initialization.
  2. Missing Boundary Checks: Without explicit coordinate clamping, moving off the grid edge generates negative indices or causes out-of-bounds runtime exceptions.
  3. Coordinate Collision: Reusing private temporary variables (like tmpX, tmpY) for both grid-step math and world-space pixel scaling can cause unintended positional offsets.

The Modern Approach: Unity Grid and Tilemap Components

Introduced in Unity 2017.2, the built-in Grid and Tilemap system eliminates manual index conversion and pixel math in favor of vector-based cell coordinates (Vector3Int).

using UnityEngine;

public class ModernGridMovement : MonoBehaviour
{
    public Grid grid;
    private Vector3Int currentCell;

    void Start()
    {
        // Snap to the nearest grid cell on start
        currentCell = grid.WorldToCell(transform.position);
        transform.position = grid.GetCellCenterWorld(currentCell);
    }

    public void MoveInDirection(Vector2Int direction)
    {
        // 1. Calculate target cell coordinate
        Vector3Int targetCell = currentCell + (Vector3Int)direction;

        // 2. Apply movement using Unity's native coordinate translation
        currentCell = targetCell;
        transform.position = grid.GetCellCenterWorld(currentCell);
    }
}

Manual System vs Unity Grid Component

FeatureManual 1D Array SystemUnity Grid Component
World PositionManual calculation (tmpX * tileSize.x)Built-in grid.CellToWorld() / GetCellCenterWorld()
Input ConversionCustom screen-to-index logicNative grid.WorldToCell()
Data LayoutFlat 1D ArrayMulti-layered 2D Tilemaps (Vector3Int)
Boundary HandlingManual checks (if (x < width))Built-in API (tilemap.HasTile(cell))
Best Use CasePure AI simulations, custom pathfinding2D top-down, tactical RPGs, and platformers

Using the native Grid component eliminates custom coordinate translation layers, reduces boilerplate code, and integrates directly with Unity's visual tilemap editing workflow.