Getting location of mouse on a grid - c#

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.

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]
}
}
}

Related

how to draw Cube using OpenTK & OpenGL in C#

I'm in crisis about draw Cube, as the title says.
I tried the graphic only in Unity. But I was done. Using OpenTK and OpenGL in C#.
It was successful to draw the sphere by inputting the value.
Draw the values of the array as you type.
Ex) 2by2 Array =>
oo
oo
this is my code about draw Sphere
void DrawSphere()
{
OpenTK.Graphics.OpenGL.GL.Enable(OpenTK.Graphics.OpenGL.EnableCap.Lighting);
OpenTK.Graphics.OpenGL.GL.Enable(OpenTK.Graphics.OpenGL.EnableCap.Light0);
OpenTK.Graphics.OpenGL.GL.Enable(OpenTK.Graphics.OpenGL.EnableCap.Normalize);
OpenTK.Graphics.OpenGL.GL.Enable(OpenTK.Graphics.OpenGL.EnableCap.ColorMaterial);
//OpenTK.Graphics.OpenGL.GL.Enable(OpenTK.Graphics.OpenGL.EnableCap.Texture2D);
OpenTK.Graphics.OpenGL.GL.ShadeModel(OpenTK.Graphics.OpenGL.ShadingModel.Smooth);
// Draw green sphere
OpenTK.Graphics.OpenGL.GL.Color3(0.8f, 0.8f, 255.0f);
//textureid = LoadTex("dd.png");
float x, y, z;
y = 0.0F;
x = 0.0F;
x = (((Properties.Settings.Default.simulRow * camera.rowGap) - camera.rowGap) / 2) * -1.0F;
for (int i = 0; i < Properties.Settings.Default.simulRow; i++)
{
z = (((Properties.Settings.Default.simulCol * camera.colGap) - camera.colGap) / 2) * -1.0F;
for (int j = 0; j < Properties.Settings.Default.simulCol; j++)
{
//y = ballImage[i, j].height / camera.calibrate_div;
y = (camera.calibrate_div / 2.0f) - Math.Abs(ballImage[i, j].current_height);
//System.Diagnostics.Debug.WriteLine(ballImage[0, 0].current_height);
OpenTK.Graphics.OpenGL.GL.PushMatrix();
OpenTK.Graphics.OpenGL.GL.Translate(x, y, z);
//OpenTK.Graphics.OpenGL.GL.BindTexture(OpenTK.Graphics.OpenGL.TextureTarget.Texture2D, textureid);
//OpenTK.Graphics.Glu.QuadricTexture(esfera, true);
OpenTK.Graphics.OpenGL.GL.Rotate(90, 1.0f, 0.0f, 0.0f);
//OpenTK.Graphics.OpenGL.GL.Rotate(0.0f, 1.0f, 1.0f, 1.0f);
OpenTK.Graphics.Glu.Sphere(esfera, 1.0f, 24, 24);
//OpenTK.Graphics.Glu.Tex(esfera, 1.0f, 24, 24);
OpenTK.Graphics.OpenGL.GL.PopMatrix();
if (i == 5 && j == 5)
{
// OpenTK.Graphics.Glu.Sphere(esfera, 100.0f, 24, 24);
}
z += camera.rowGap;
}
x += camera.colGap;
}
}

Color Table Algorithm

I've been searching for just over a week now on how to create something like this.
I have the code and for loops to create each Panel by X, and Y coords and everything. Each Panel is part of an array and starts at 0 at top left and ends at 90 at top right, but I don't care how its done as long as its done and its panels and works. The colors don't need to be the same but something similar so that I can have a fullscreen color picker. If someone knows some code to take one specific color and make it brighter ten times to set the panels backColor, using Color.FromARGB or just the Color class, to then please help me out. Thank you.
(This is a app I'm making for windows tablet and is touchscreen. The purpose of the app is to be fullscreen and not reviele that its a windows tablet, There for I have to make the color picker myself and cannot use the built in color dialog.)
For best control I suggest using a color calculation function.
There are many out there; here is one I use:
Color HsvToRgb(double h, double S, double V)
{
/// Convert HSV to RGB
/// h is from 0d - 360d
/// s,v values are 0d - 1d
/// r,g,b values are 0 - 255
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
double f = hue / 60 - Math.Floor(hue / 60);
value = value * 255;
int v = Convert.ToInt32(value);
int p = Convert.ToInt32(value * (1 - saturation));
int q = Convert.ToInt32(value * (1 - f * saturation));
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
if (hi == 0) return Color.FromArgb(255, v, t, p);
else if (hi == 1) return Color.FromArgb(255, q, v, p);
else if (hi == 2) return Color.FromArgb(255, p, v, t);
else if (hi == 3) return Color.FromArgb(255, p, q, v);
else if (hi == 4) return Color.FromArgb(255, t, p, v);
else return Color.FromArgb(255, v, p, q);
}
Do note the input ranges!!
Now it is easy to setup a Color array at class level:
int width = 10;
int height = 9;
Color[,] colors;
And fill it:
void loadColors()
{
colors = new Color[width, height];
// load greys
for (int i = 0; i < width; i++ ) colors[i, 0] = HsvToRgb(0f, 0f, 1f * i / width);
// load bright stripe:
for (int i = 0; i < width; i++) colors[i, 1] = HsvToRgb(i* 360f / width, 0.33f, 1f);
// load matrix:
for (int j = 2; j < height; j++)
for (int i = 0; i < width; i++)
colors[i, j] = HsvToRgb(i * 360f / width, 1f, 1f * (height - j + 2) / height);
}
From this is is a snap to set the BackColors of your Panels.
Here is a Form.Paint function, I used to create the above screenshot:
private void Form1_Paint(object sender, PaintEventArgs e)
{
int w = ClientSize.Width / width;
int h = ClientSize.Height / height;
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
using (SolidBrush brush = new SolidBrush(colors[i,j]))
e.Graphics.FillRectangle(brush, i * w, j * h, w, h);
}
}
Of course it is as simple as changing two numbers to make a finer grid, here 20x20:
Also note how the even spacing of hues doesn't really work well, as neither the human eye nor our common display systems are equally sensitive to changes in hues across the spectrum..
The eye is actually rather sensitive to greenish hues
the just-noticeable difference in wavelength varies from about 1 nm in
the blue-green and yellow wavelengths, to 10 nm and more in the longer
red and shorter blue wavelengths
but our monitors do a pretty bad job at creating different green hues..
Using an adapted list of perceptionally evenly spaced hues might help, depending on what you want..
Using this one-liner:
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int hue = (int) ((Bitmap)pictureBox1.Image).GetPixel(e.X, e.Y).GetHue();
}
on the image above gives us one such list of hues:
20 32 41 50 58 72 133 163 170 177 183 190 197 206 269 288 307 324 334 346
I have modified it a little, maybe to make it work better with my monitor:
List<int> hues = new List<int>
{ 20, 32, 41, 50, 58, 72, 133, 162, 180, 188, 195, 205, 215, 223, 246, 267, 288, 300, 320, 346 };
And changing the above code (keeping width = 20) to
HsvToRgb(hues[i],..
results in this:
Update: I have replaced the HsvToRgb function by a greatly simplified one.
With this answer you'll get the possibility to use the HSB representation of a color (maybe take also a look here).
By using this you can for the first row use a random hue, a zero saturation and a brightness going from 1.0 to 0.0 in the amount of needed steps. For the other rows you have to take 1.0 for the saturation and increase the hue from 0 to 360 in the same amount of steps and also increase the saturation from 0.0 to 1.0 per row.
I just put an example together:
private void OnResize(object sender, EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
UpdateImage(e.Graphics);
}
private void UpdateImage(Graphics graphics)
{
var columns = 10;
var rows = 8;
var hueSteps = 360 / columns;
var columnSteps = 1.0F / columns;
var width = Width / columns;
var height = Height / (rows + 1);
for (int i = 0; i < columns; i++)
{
var gray = ColorExtensions.FromAhsb(255, 0, 0, columnSteps * i);
using (var brush = new SolidBrush(gray))
{
graphics.FillRectangle(brush, width * i, 0, width, height);
}
}
for (int i = 0; i < columns; i++)
{
for (int j = 1; j <= rows; j++)
{
var color = ColorExtensions.FromAhsb(255, hueSteps * i, 1, columnSteps * j);
using (var brush = new SolidBrush(color))
{
graphics.FillRectangle(brush, width * i, height * j, width, height);
}
}
}
}
The result is not exact the same, but that would be just a matter of re-arrange the loops:

Changing Levels By Choices

Hey so I have this code here and what i am trying to do is make 2 more similar levels so when i have tile map 2 and 3 i would have a menu where the player could choose to play on a certain map... i am wondering how i would make this menu, would you please give me some insight on where to begin what type of code i could use etc.
Simple choice menu look:
Levels
Level 1
Level 2
Level 3
and the user would click on it and it would trigger/open one of the tilemaps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MarsCitadel
{
static class Tilemap
{
#region declarations
public const int TileWidth = 32;
public const int TileHeight = 32;
public const int MapWidth = 50;
public const int MapHeight = 50;
public const int FloorTileStart = 0; // 32 x 32 rectangle from sprite sheet
public const int FloorTileEnd = 3;
public const int WallTileStart = 4;
public const int WallTileEnd = 7;
static private Texture2D texturebarrens;
static private Texture2D textureroad;
//static private List<Rectangle> tiles = new List <Rectangle> ();
static private int[,] mapSquares = new int[MapWidth, MapHeight];
static private Random rand = new Random();
#endregion
#region intialization
static public void intialization(Texture2D tiletexture, Texture2D tiletexture2)
{
texturebarrens = tiletexture;
textureroad = tiletexture2;
//tiles.Clear();
//tiles.Add(new Rectangle(0, 0, TileWidth, TileHeight));
for (int x = 0; x < MapWidth; x++)
{
for (int y = 0; y < MapHeight; y++)
{
mapSquares[x, y] = FloorTileStart;
}
}
GenerateRandomMap();
}
#endregion
#region information about map squares
static public int getsquareatpixelX(int pixelX)
{
return pixelX / TileWidth;
}
static public int getsquareatpixelY(int pixelY)
{
return pixelY / TileHeight;
}
static public Vector2 getsquarebypixel(Vector2 pixellocation)
{
return new Vector2(getsquareatpixelX((int)pixellocation.X), getsquareatpixelY((int)pixellocation.Y));
}
static public Vector2 Getsquarecenter(int squareX, int squareY)
{
return new Vector2((squareX * TileWidth) + (TileWidth / 2), (squareY * TileHeight) + (TileHeight / 2));
}
static public Vector2 Getsquarecenter(Vector2 square)
{
return Getsquarecenter((int)square.X, (int)square.Y);
}
static public Rectangle Squareworldrectangle(int x, int y)
{
return new Rectangle(x * TileWidth, y * TileHeight, TileWidth, TileHeight);
}
static public Rectangle Squareworldrectangle(Vector2 square)
{
return Squareworldrectangle((int)square.X, (int)square.Y);
}
public static Rectangle Squarescreenrectangle(int x, int y)
{
return Camera.Transform(Squareworldrectangle(x, y));
}
public static Rectangle Squarescreenrectangle(Vector2 square)
{
return Squareworldrectangle((int)square.X, (int)square.Y);
}
#endregion
#region information about map tiles
static public int GetTileAtSquare(int tileX, int tileY)
{
if (((tileX >= 0) && (tileX <= MapWidth)) && ((tileX >= 0) && (tileX <= MapHeight)))
{
return mapSquares[tileX, tileY];
}
else return -1;
}
static public void SetTileAtSquare(int tileX, int tileY, int tile)
{
if (((tileX >= 0) && (tileX <= MapWidth)) && ((tileX >= 0) && (tileX <= MapHeight)))
{
mapSquares[tileX, tileY] = tile;
}
}
static public int GetTileAtPixel(int pixelX, int pixelY)
{
return GetTileAtSquare(getsquareatpixelX(pixelX), getsquareatpixelY(pixelY));
}
static public int GetTileAtPixel(Vector2 pixelLocation)
{
return GetTileAtPixel((int)pixelLocation.X, (int)pixelLocation.Y);
}
static public bool IsWallTile(int tileX, int tileY)
{
int tileindex = GetTileAtSquare(tileX, tileY);
if (tileindex == -1) return false;
return tileindex >= WallTileStart;
}
static public bool IsWallTile(Vector2 square)
{
return IsWallTile((int)square.X, (int)square.Y);
}
static public bool IsWallTileByPixel(Vector2 pixelLocation)
{
return IsWallTile(getsquareatpixelX((int)pixelLocation.X), getsquareatpixelY((int)pixelLocation.Y));
}
#endregion
#region drawing
static public void Draw(SpriteBatch spritebatch)
{
//int startX = getsquareatpixelX((int)Camera.Position.X);
//int endX = getsquareatpixelX((int)Camera.Position.X + Camera.ViewPortWidth);
//int startY = getsquareatpixelY((int)Camera.Position.Y);
//int endY = getsquareatpixelY((int)Camera.Position.Y + Camera.ViewPortHeight);
int startX = 0; int endX = 50;
int startY = 0; int endY = 50;
for (int x = startX; x <= endX; x++)
{
for (int y = startY; y <= endY; y++)
{
if ((x >= 0) && (y >= 0) && (x < MapWidth) && (y < MapHeight))
{
spritebatch.Draw(texturebarrens, new Rectangle(x * 32, y * 32, 32, 32), Color.White);
}
}
}
spritebatch.Draw(textureroad, new Rectangle(0 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(1 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(2 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(3 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(4 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(5 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(6 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(7 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(8 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(9 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(10 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(11 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(12 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(13 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(14 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(15 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(16 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(17 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(18 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(19 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(20 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(21 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(22 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(23 * 32, 7 * 32, 32, 32), Color.White);
spritebatch.Draw(textureroad, new Rectangle(24 * 32, 7 * 32, 32, 32), Color.White);
}
#endregion
#region map generation
static public void GenerateRandomMap()
{
int WallchancePerSquare = 10;
int floorTile = rand.Next(FloorTileStart, FloorTileEnd + 1);
int wallTile = rand.Next(WallTileStart, WallTileEnd + 1);
for (int x = 0; x < MapWidth; x++)
{
for (int y = 0; y < MapHeight; y++)
{
mapSquares[x, y] = floorTile;
// if (x == 0 || y == 0 || x == MapWidth - 1 || y == MapHeight - 1)
//{
//mapSquares[x, y] = wallTile;
// continue;
// }
if (x == 1 || y == 1 || x == MapWidth - 2 || y == MapHeight - 2)
{
continue;
}
if (rand.Next(0, 100) < WallchancePerSquare)
{
mapSquares[x, y] = wallTile;
}
}
}
}
#endregion
}
}
Make the Tilemap class abstract, then each version of your map can be a different sub-class of Tilemap (there may be other ways to optimize this, try looking up some design pattern such as "decorator" or "strategy" patterns). Create a Menu class which allows the user to select a map, say with a variety of buttons. Clicking a button should then instantiate the corresponding sub-class of Tilemap, any other code can refer to these objects as Tilemap without knowing which sub-class is implemented.

Drawing a layered tile based map

So I'm trying to draw a layered tile based map, as the title says. I have this so far. The tiles i am using are (32, 32). It's currently drawing only 1 type of tile as the whole tile map. When it should be drawing out several different types of tiles to make a map.
for (int layers = 0; layers < map.Layers.Count; layers++) {
for (var i = 0; i < map.Layers[layers].Tiles.Count; i++) {
int gid = map.Layers[layers].Tiles[i].Gid;
if (gid != 0) {
int tileFrame = gid - 1;
int row = tileFrame / (map.Height / tileHeight);
float x = (i % map.Width) * map.TileWidth;
float y = (float)Math.Floor(i / (double)map.Width) * map.TileHeight;
Rectangle tilesetRec = new Rectangle(0, 0, 32, 32);
for (int j = 0; j < tileSets.Count; j++) {
for (int k = 0; k < tileSets[j].Tiles.Count; k++) {
spriteBatch.Draw(tileSets[j].Tiles[k].Image.Texture, new Rectangle((int)x, (int)y, 32, 32), Color.White);
}
}
}
}
}
This is not entirely my code this is someone elses that i have tried to build on apparently it worked for the person for drawing one layer. This is the original code:
for (var i = 0; i < _map.Layers[0].Tiles.Count; i++) {
int gid = _map.Layers[0].Tiles[i].Gid;
// Empty tile, do nothing
if (gid == 0) {
} else {
int tileFrame = gid - 1;
int row = tileFrame / (_tileset.Height / _tileHeight);
float x = (i % _map.Width) * _map.TileWidth;
float y = (float)Math.Floor(i / (double)_map.Width) * _map.TileHeight;
Rectangle tilesetRec = new Rectangle(_tileWidth * tileFrame, _tileHeight * row, 32, 32);
spriteBatch.Draw(_tileset, new Rectangle((int)x, (int)y, 32, 32), tilesetRec, Color.White);
}
}
Your problem is that for each tile position you seem to be drawing all tiles in all tilesets. The variables tileFrame, row and tilesetRec, which were used to render the specific tile in the original code, are not used in your first snippet.

Selection texture on tiles causing performance issues

public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector2 mouseCoord = GetMouseTilePosition();
if (mouseCoord.X > 0)
{
spriteBatch.Draw(selection, tileRect = new Rectangle((int)mouseCoord.X * 64, (int)mouseCoord.Y * 64, 64, 64),
Color.White);
}
spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
}
}
public Vector2 GetMouseTilePosition()
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (IsMouseInsideTile(x, y))
{
return new Vector2(x, y);
}
}
}
return new Vector2(-1, -1);
}
public bool IsMouseInsideTile(int x, int y)
{
MouseState MS = Mouse.GetState();
return (MS.X >= x * 64 && MS.X <= (x + 1) * 64 &&
MS.Y >= y * 64 && MS.Y <= (y + 1) * 64);
}
It is very cpu intensive. Is there a better way to do this code? Also I have a camera how can I change this to factor that in so I get the actual mouse position
Jon Skeet is right, you could directly call IsMouseInsideTile() instead of looping through your array several times. (Currently, you're checking where the mouse is in the whole tile array, for each tile, instead of only checking the current tile you're in).
public void Draw(SpriteBatch spriteBatch)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (IsMouseInsideTile(x, y))
{
spriteBatch.Draw(selection, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64),
Color.White);
}
}
}
I'm sorry, it's all my fault, I submitted this code quickly earlier without double checking. This new version should improve your performance drastically.

Categories