MonoGame - Get grid cell position where the cursor is in a world that is relative to a matrix

I am just coding my game and I stuck with getting the cell position.
I need to get cell position where the cursor is, and everything is drawing relative to camera matrix.

I’ve tried many things - doing many stuff with Vector2 positions, matrix itself, and I got nowhere.

Any help is appreciated.

Code that tries to get grid cell position:

                    // Getting view matrix
                    var viewMatrix = cam.GetTransform();
                    Vector2 worldPosition = Vector2.Transform(mouse.Position.ToVector2(), Matrix.Invert(viewMatrix));

                    // Getting the grid cell position where cursor is
                    int width = 80;
                    int height = 80;
                    int size = 64;

                    for (int forX = 0; forX < width; forX++)
                    {
                        for (int forY = 0; forY < height; forY++)
                        {
                            int mouseXmin = (size * forX) + 1;
                            int mouseXmax = mouseXmin + 63;
                            int mouseYmin = (size * forY) + 1;
                            int mouseYmax = mouseYmin + 63;

                            Vector2 minVector = Vector2.Transform(new Vector2(mouseXmin, mouseYmin), Matrix.Invert(viewMatrix));
                            Vector2 maxVector = Vector2.Transform(new Vector2(mouseXmax, mouseYmax), Matrix.Invert(viewMatrix));

                            if (worldPosition.X > minVector.X && worldPosition.X < maxVector.X
                                && worldPosition.Y > minVector.Y && worldPosition.Y < maxVector.Y)
                            {
                                // Some debug stuff, this is where I got that it does not work beacuse of matrix magic
                                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,
                                       null, null, null, null, viewMatrix);
                                debugRectangle = new Rectangle((int)minVector.X, (int)minVector.Y, (int)maxVector.X, (int)maxVector.Y);
                                spriteBatch.End();
                            }
                        }
                    }

Drawing code:

            // Getting view matrix
            var viewMatrix = cam.GetTransform();

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,
                                       null, null, null, null, viewMatrix);

            // Drawing grid
            for (float x = 0; x < 80; x++)
            {
                int length = 64 * 79;
                Rectangle rectangle = new Rectangle((int)(64 * x), 0, 1, length);
                spriteBatch.Draw(px, rectangle, Color.White);
            }

            for (float y = 0; y < 80; y++)
            {
                int length = 64 * 79;
                Rectangle rectangle = new Rectangle(0, (int)(64 * y), length, 1);
                spriteBatch.Draw(px, rectangle, Color.White);
            }

            // Drawing blocks
            for (int forX = 0; forX < 80; forX++)
            {
                for (int forY = 0; forY < 80; forY++)
                {
                    Block block = blocks[forX, forY];
                    if (block == null) continue;
                    int x = (64 * forX) + (1 * (forX + 1));
                    int y = (64 * forY) + (1 * (forX + 1));
                    switch (block.type)
                    {
                        case Block.BlockType.AND:
                            spriteBatch.Draw(and, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.NAND:
                            spriteBatch.Draw(nand, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.NOR:
                            spriteBatch.Draw(nor, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.NOT:
                            spriteBatch.Draw(not, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.NXOR:
                            spriteBatch.Draw(nxor, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.OR:
                            spriteBatch.Draw(or, new Vector2(x, y), Color.White);
                            break;
                        case Block.BlockType.WIRE:
                            DrawRectangle(new Rectangle(x + 15, y + 15, 35, 35), Color.Black);
                            if (block.active) DrawFilledRectangle(new Rectangle(x + 17, y + 17, 31, 31), Color.Green);
                            else DrawFilledRectangle(new Rectangle(x + 17, y + 17, 33, 33), Color.Red);
                            break;
                        case Block.BlockType.XOR:
                            spriteBatch.Draw(xor, new Vector2(x, y), Color.White);
                            break;
                    }
                }
            }

            spriteBatch.End();

Camera:

    public class Camera
    {
        public Camera()
        {
            Zoom = 1;
            Position = Vector2.Zero;
            Rotation = 0;
            Origin = Vector2.Zero;
            Position = Vector2.Zero;
        }

        public float Zoom { get; set; }
        public Vector2 Position { get; set; }
        public float Rotation { get; set; }
        public Vector2 Origin { get; set; }

        public void Move(Vector2 direction)
        {
            Position += direction;
        }

        public Matrix GetTransform()
        {
            var translationMatrix = Matrix.CreateTranslation(new Vector3(Position.X, Position.Y, 0));
            var rotationMatrix = Matrix.CreateRotationZ(Rotation);
            var scaleMatrix = Matrix.CreateScale(new Vector3(Zoom, Zoom, 1));
            var originMatrix = Matrix.CreateTranslation(new Vector3(Origin.X, Origin.Y, 0));

            return translationMatrix * rotationMatrix * scaleMatrix * originMatrix;
        }
    }

To get the world position of the mouse cursor:

    public Vector3? TranslateScreenPointToWorld(Vector2 screenPos)//screenPos is mousePos
    {
        //depending on how the world is oriented in regards to your map,
            //the 1 may have to go in the X or Y position
        //for example, if when you move towards and away from your map
            //the Z value changes, put the 1 in the Z position
        Plane gridPlane = new Plane(new Vector3(0, 0, 1), 0);

        Vector3 nearSource = new Vector3(screenPos.X, screenPos.Y, 0f);
        Vector3 farSource = new Vector3(screenPos.X, screenPos.Y, 1f);

        Vector3 nearPoint = Graphics.GraphicsDevice.Viewport.Unproject(nearSource,
            Projection, View, Matrix.Identity);

        Vector3 farPoint = Graphics.GraphicsDevice.Viewport.Unproject(farSource,
            Projection, View, Matrix.Identity);

        Vector3 direction = farPoint - nearPoint;
        direction.Normalize();
        Ray pickRay = new Ray(nearPoint, direction);
        float? position = pickRay.Intersects(gridPlane);

        if (position.HasValue)
        {
            return pickRay.Position + pickRay.Direction * position.Value;
        }
        else
        {
            return null;
        }
    }

To get the grid cell:

Vector3? worldPosition = TranslateScreenPointToWorld(mousePos);//mousePos is screenPos

if (worldPosition.HasValue && !float.IsNaN(worldPosition.Value.X) && !float.IsNaN(worldPosition.Value.Y))
{
    //again just like the plane in the previous code, in regards to the
    //position of the 1, you may need to use different worldPosition.Value.X/Y/Z
    //for example: if the 1 goes in the Z position, use the X and Y
    Vector2 mapPosition = new Vector2(worldPosition.Value.X, worldPosition.Value.Y);

    Vector2 gridPosition = (mapPosition - map.startPosition) / tile.dimensions;//map.startPosition is for if the map is offset in your world
    
    //and here it is
    blocks[(int)gridPosition.X, (int)gridPosition.Y] ... stuff
}

I’m hoping this works. I haven’t used spriteBatch for gameplay stuff in awhile.

Ok, I’ll try this today. And spriteBatch things was just for debugging

Nope, does not work.

I’ve done it.
Here is my new working code:

                // Variables
                int size = 80;
                int cell = 64;

                // Minimum positions on X axis
                List<int> minPosX = new List<int>() { 1 };
                for (int x = 0; x < (size * cell) + 1; x++)
                    if ((x - 1) % cell == 0) minPosX.Add((int)cam.Position.X + x);

                minPosX.Add((int)cam.Position.X + 1);

                // Minimum positions on Y axis
                List<int> minPosY = new List<int>() { 1 };
                for (int x = 0; x < (size * cell) + 1; x++)
                    if ((x - 1) % cell == 0) minPosY.Add((int)cam.Position.Y + x);

                minPosY.Add((int)cam.Position.Y + 1);

                // Getting cursor's position in the grid
                int biggestCellX = -1;
                int biggestCellY = -1;

                int realCellX = -1;
                int realCellY = -1;

                // Getting view matrix and mouse position
                Matrix matrix = cam.GetTransform();
                Vector2 mousePos = Vector2.Transform(new Vector2(mouse.X + -(int)cam.Position.X, mouse.Y + -(int)cam.Position.Y), matrix);

                for (int cellX = 0; cellX < minPosX.Count; cellX++)
                {
                    for (int cellY = 0; cellY < minPosY.Count; cellY++)
                    {
                        int x = minPosX[cellX];
                        int y = minPosY[cellY];

                        if (mousePos.X > x && mousePos.X < (x + 63)
                            && mousePos.Y > y && mousePos.Y < (y + 63))
                        {
                            if (biggestCellX < cellX) biggestCellX = cellX;
                            if (biggestCellY < cellY) biggestCellY = cellY;

                            debugRectangle = new Rectangle(x, y, 63, 63);
                        }
                    }
                }

                if (biggestCellX == 81 && biggestCellY == 81)
                {
                    realCellX = 0;
                    realCellY = 0;
                }
                else if (biggestCellX == 81)
                {
                    realCellX = 0;
                    realCellY = biggestCellY - 1;
                }
                else if (biggestCellY == 81)
                {
                    realCellX = biggestCellX - 1;
                    realCellY = 0;
                }
                else if (biggestCellX != -1 && biggestCellY != -1)
                {
                    realCellX = biggestCellX - 1;
                    realCellY = biggestCellY - 1;
                }

                // Blocks stuff
                if (gameState == GameState.BUILDING
                    && realCellX != -1
                    && realCellY != -1
                    && blocks[realCellX, realCellY] != null
                    && blocks[realCellX, realCellY].canBeDeleted) blocks[realCellX, realCellY] = null;