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);
}
}
}
}
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.