0

So I'm stuck on how to be able to convert my mouse position in monogame/XNA to a position of my grid. What I am trying to achieve is basically to change the color of the rectangle on that specific cell in the grid to a different color when I click on them.

This is my first time working on a grid system and I don't really have a clue on how to do this.

Here is how I built my grid. What basically happens here is I first populate every cell in the grid with 0s. And depending on what value I assign in the update method in the Game1 class, the color of the rectangle will change.

Thank you!

 public int[,] gridCell;
    Texture2D texture;
    public Rectangle rect;
    int col;
    int row;
    const int gridSize = 32;



    //Initializes the constructor
    public Grid(int sizeCol, int sizeRow)
    {
        //texture = sprite;
        col = sizeCol;
        row = sizeRow;
        gridCell = new int[col, row];

        for(int i = 0; i<col;i++)
        {
           for(int j = 0; j<row;j++)
            {
                gridCell[i, j] = 0;
            }
        }
    }


    public void Draw(SpriteBatch spritebatch)
    {
        for (int i = 0; i <= col-1; i++)
        {
            for (int j = 0; j <= row-1; j++)
            {
                if (gridCell[i, j] == 0)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.CornflowerBlue, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }

                else if( gridCell[i,j] == 1)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Yellow, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }
                else if (gridCell[i, j] == 2)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Red, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }
                else if (gridCell[i, j] == 3)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Purple, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }
                else if (gridCell[i, j] == 4)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Blue, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }
                else if (gridCell[i, j] == 5)
                {
                    spritebatch.FillRectangle(i * 32, j * 32, 31, 31, Color.Black, 0f);
                    spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);
                }
            }
        }
    }
Favonius
  • 49
  • 7
  • I'm not overly familiar with MonoGame, but you may need to translate the mouse cursor's position into the game world's (your grid) coordinate system which is fairly common with other game engines so keep that in mind. You need to test if the mouse position is in/collides with grid cell rectangles. To do that, check out [Rectangle.Contains Method](https://msdn.microsoft.com/en-us/library/microsoft.xna.framework.rectangle.contains.aspx). You can then test the Mouse's X/Y coordinates against your grid cells. – Jonathon Ogden Apr 22 '16 at 10:16
  • "change the color of the rectangle on that specific cell in the grid" but you only have 1 rectangle for the entire grid of cells? Why don't you allocate one rectangle for each cell and just draw those rectangles? – libertylocked Apr 22 '16 at 16:03

2 Answers2

2

Ok, here is how it goes: lets say your grid's one square is 8x8. Position of your mouse can be between 8 and 0, and you need it to be only 0/8/16/24/... When you divide mouse position by 8 (lets say Mposition is 4x20), you'll get 0.5x2.5, and if you multiply that with 8, you'll get 4x20 again, BUT: if you truncate division result, youll get 0x2, and that multiplied by 8 is 0x16, so that (0x16) is the real position of the square that mouse is inside of, and 0x2 is the matrix position of your mouse. Here is a simple function that will get you what you need:

public Vector2 PositionByGrid (int gridSize)
    {
        Vector2 result = new Vector2(MouseState.GetState().X, MouseState.GetState().Y);
        result.X = (int)(result.X / gridSize) * gridSize;
        result.Y = (int)(result.Y / gridSize) * gridSize;
        return result;
    }

This function will return position of the square. If you want the position in matrix, just put result.X = (int)(result.X / gridSize); instead of result.X = (int)(result.X / gridSize) * gridSize;

EDIT:
As @Slubberdegullion suggested, here is the function if your grid is not in squares, but in rectangles (same principle for the matrix applies):

public Vector2 PositionByGrid (int gridWidth, int gridHeight)
    {
        Vector2 result = new Vector2(MouseState.GetState().X, MouseState.GetState().Y);
        result.X = (int)(result.X / gridWidth) * gridWidth;
        result.Y = (int)(result.Y / gridHeight) * gridHeight;
        return result;
    }



EDIT 2: This is a suggestion
Also, you could shorten the Draw function, to look like this (explanation in Suggestion No2):

public void Draw(SpriteBatch spritebatch)
{
    for (int i = 0; i <= col-1; i++)
    {
        for (int j = 0; j <= row-1; j++)
        {
            Color newColor;
            switch(gridCell[i, j])
            {
                case 0: newColor = Color.CornflowerBlue; break;
                case 1: newColor = Color.Yellow; break;
                case 2: newColor = Color.Red; break;
                case 3: newColor = Color.Purple; break;
                case 4: newColor = Color.Blue; break;
                case 5: newColor = Color.Black; break;
                default: newColor = Color.White; break;
            }
            spritebatch.FillRectangle(i * 32, j * 32, 31, 31, newColor, 0f);
            spritebatch.DrawRectangle(new Vector2(i * 32, j * 32), new Vector2(32, 32), Color.Black, 1f);

        }
    }
}

It is true that this will use a bit more RAM (equal to adding 4 new integer variables to the game because color is a Vector4 basicaly but with int instead of float) and CPU time, but that cost is very low for the cost of your games integrity and readability.
Suggestion No2: From your code I beleave I see that you are a beginner, and with that said, I feel my obligation is to tell you not to repeat the same (group of) lines of code, in code. Instead, create a function / do what I did with your Draw function / etc. Your way, if you get to the point where you have to change 1 thing, you'll have to change it in X places. And what if then you have to change it again, or a couple more times? By keeping repetative code in one function, when need arises, you'll have to change that 1 thing only in that function.

Monset
  • 648
  • 5
  • 25
  • 1
    This works if the width and height are the same. Otherwise, replace gridSize with the proper dimensions. This should be the accepted answer if you are wondering which of the two you should accept. – Slubberdegullion Apr 22 '16 at 18:29
  • Awesome, this is way more than what I needed. Thank you for helping me out with this! – Favonius May 02 '16 at 03:36
0

Generate an array of collision rectangles for your grid when you construct your grid.

Rectangle[,] gridRects = new Rectangle[row, col];

for (int i = 0; i < row; i++)
{
    for (int j = 0; j < col; j++)
    {
        gridRects[i,j] = new Rectangle(i * gridSize, j * gridSize, gridSize, gridSize);
    }
}

Then for every frame, in Update, check for collisions

MouseState ms = Mouse.GetState();

for (int i = 0; i < row; i++)
{
    for (int j = 0; j < col; j++)
    {
        if (gridRects.Contains(ms.X, ms.Y))
        {
            // Mouse is on gridCell[i,j]
        }
    }
}
libertylocked
  • 892
  • 5
  • 15