Unity/C# - Grids - Cell Points


Another post about grids! Yeah, I know they are pretty old but they are so interesting and have much stuff about them that I think it is good to talk about it. Ok, so far this is our GridMath class (I renamed from Grid because it is already used by Unity3D)

public static class GridMath
{
    public const float DISCRETE_SIZE = 1.0f;

    public static Vector4 RightVector = new Vector4(1, 0, 0, 0) * DISCRETE_SIZE;
    public static Vector4 UpVector = new Vector4(0, 1, 0, 0) * DISCRETE_SIZE;

    public static Matrix4x4 GridToWorldMatrix => new Matrix4x4(
        RightVector,
        UpVector,
        new Vector4(0, 0, 0, 0),
        new Vector4(0, 0, 0, 0));

    public static Vector3 GridToWorld(Vector2Int gridPosition)
    {
        return GridToWorldMatrix * (Vector2)gridPosition;
    }
    public static Vector2Int WorldToGrid(Vector3 worldPosition)
    {
        var worldCoord = GridToWorldMatrix.inverse * worldPosition;
        return new Vector2Int(Mathf.RoundToInt(worldCoord.x), Mathf.RoundToInt(worldCoord.y));
    }
    public static Vector3 GetCellCenter(Vector2Int gridPosition) => GridToWorld(gridPosition);

    public static IEnumerable<Vector2Int> Enumerate(this RectInt rect)
    {
        for (int i = rect.xMin; i < rect.xMax; i++)
            for (int j = rect.yMin; j < rect.yMax; j++)
                yield return new Vector2Int(i, j);
    }

    public static IEnumerable<Vector2Int> VonNeumannNeighborhood(this Vector2Int coord)
    {
        yield return coord + new Vector2Int(1, 0);
        yield return coord + new Vector2Int(0, 1);
        yield return coord + new Vector2Int(-1, 0);
        yield return coord + new Vector2Int(0, -1);
    }

    public static IEnumerable<Vector2Int> MooreNeighborhood(this Vector2Int coord)
    {
        foreach (var neighbor in VonNeumannNeighborhood(coord))
            yield return neighbor;

        yield return coord + new Vector2Int(1, 1);
        yield return coord + new Vector2Int(-1, 1);
        yield return coord + new Vector2Int(-1, -1);
        yield return coord + new Vector2Int(1, -1);
    }
}

For our grid, we will take the transformation from grid-space to world-space as the center of each grid cell. To get the 4 corners we just need to add half-diagonals. Since transformation is using a matrix composed of 2 vectors, we need to define the diagonals in terms of these vectors, so that it works also for dimetric, trimetric or isometric grid.

    public static Vector3 GetCellCenter(Vector2Int gridPosition) => GridToWorld(gridPosition);

    public static IEnumerable<Vector3> GetWorldCorners(Vector2Int gridPos)
    {
        var center = GetCellCenter(gridPos);
        yield return center + (RightVector + UpVector) * 0.5f;
        yield return center + (RightVector - UpVector) * 0.5f;
        yield return center + (- RightVector + UpVector) * 0.5f;
        yield return center + (- RightVector - UpVector) * 0.5f;
    }

This should work for the majority of grid types. Another way to do that would be to multiply the up and right world-vectors by the grid-transformation matrix, that should give you the UpVector and RightVector. To get the laterals we just need to connect corners.

public static IEnumerable<Tuple<Vector3, Vector3>> GetWorldLaterals(Vector2Int gridPos)
{
    var corners = GetWorldCorners(gridPos).ToArray();
    yield return new Tuple<Vector3, Vector3>(corners[0], corners[1]);
    yield return new Tuple<Vector3, Vector3>(corners[1], corners[2]);
    yield return new Tuple<Vector3, Vector3>(corners[2], corners[3]);
    yield return new Tuple<Vector3, Vector3>(corners[3], corners[0]);
}

Comments

Popular posts from this blog

Unity3D/C# - Asynchronous Programming - Coroutines vs await/async

C# - Simple Graph Interfaces and a MeshGraph

Unity/C# - Grids - Simple Grid Segment struct