1

My main problem is I don't understand how to get the position of the generated tiles or how to tell where the mouse is. Should I use collision to detect mouse or something else? Is there something I can do to optimize my code and make it easier to get things like the position

I took some things out of my code like loading of the textures just to make it shorter for you guys since that isn't part of the problem.

My Tile Generation Code

    public Block[] tiles = new Block[3];
    public int width, height;
    public int[,] index;
    public Rectangle tileRect;

public void Load(ContentManager content)
    {
        tiles[0] = new Block { Type = BlockType.Grass, Position = Vector2.Zero, texture = grass};
        tiles[1] = new Block { Type = BlockType.Dirt, Position = Vector2.Zero, texture = dirt};

        width = 50;
        height = 50;

        index = new int[width, height];

        Random rand = new Random();
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                index[x,y] = rand.Next(0,2);
            }
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                    spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64), 
                        Color.White);          
            }
        }  
    }

Block Properties Code

public enum BlockType
{
    Dirt,
    Grass,
    Selection
}

public class Block
{
    public BlockType Type { get; set; }
    public Vector2 Position { get; set; }
    public Texture2D texture { get; set; }
}
Corey
  • 73
  • 4
  • 13

2 Answers2

1

In the XNA Update function, you can get the mouse position using Mouse.GetState() which will give you the X and Y coordinate properties of the mouse. Just divide those by your tile size and round down (floor) to get the closest tile coordinate index.

Added Code

public static Vector2 GetGridCoordinates(MouseState mouseState, int gridSize){
    return new Vector2(
        (int)Math.Floor(mouseState.X / gridSize),
        (int)Math.Floor(mouseState.Y / gridSize)
    );
}

You could probably even make this an extension function of the MouseState class so all you'd have to do is something like:

Vector2 gridCoords = Mouse.GetState().GetGridCoordinates(MyGridSize);

But I'm probably overthinking it...

  • I like this better than the accepted answer. No need to do a double loop O(n^2) calculation and test every tile until you hit one when you can start with the mouse position and know exactly which tile spot it is in with an O(1) calculation. Not only that, but the accepted answer querys mouse position every iteration of the loop, which is unnecessary. I'm editing in code to your answer if the poster needs it, never done that before but I guess I'll give it a shot? – A-Type Mar 30 '12 at 17:41
  • @A-Type The performance issue has been addressed in another question. I've changed the code here to reflect that update. – Msonic Mar 30 '12 at 17:52
  • @A-Type: Thanks for the comment! I've used code in multiple languages that makes use of that sort of algorithm. It's easy to read and uses common math functions. Seems like the other way works just as well. – irrationalistic Apr 12 '12 at 02:43
1

This code should do the trick. You can add this method in your tile generation class. (Untested)

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

You can edit this function however you like to fit it to your needs.

Edit: I'll explain this code a little.

  • Mouse.GetState() gets the current position of the mouse, as a Vector2

  • A tile [a ,b] is at the position [a * 64, b * 64], as your draw method says

  • The tile's max x and y coordinates is at [(a + 1) * 64, (b + 1) * 64], since the texture is 64 by 64 pixels of dimensions.

  • I check the if the mouse is inside every tile. You could add a MouseHover event if you'd like.

More edits: Edited my code, based on your comment.

Even more edits: Here is the code for the Draw method:

public void Draw(SpriteBatch spriteBatch)
    {
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                    spriteBatch.Draw(tiles[index[x,y]].texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64), 
                        Color.White);
                    if(IsMouseInsideTile(x, y))
                        spriteBatch.Draw(selected.texture, tileRect = new Rectangle(x * 64, y * 64, 64, 64), 
                                        Color.White);
            }
        }  
    }
Msonic
  • 1,456
  • 15
  • 25
  • This is really helpful and it works to an extent, but I don't understand how to just get one tile, it removes all tiles that have the same texture. That happens when I do tiles[index[x,y]].texture = selection; I would like to have it drawn in the draw method instead, but I don't understand what to use for the Rectangle to get the position of that exact tile because tiles[index[x,y]].Position.X and Y doesn't work – Corey Mar 29 '12 at 18:09
  • Also, if you're trying to add a "Selected" texture, you should draw it **over** the selected tile: it will be much more simple than replacing the texture of the selected tile temporarily. – Msonic Mar 29 '12 at 18:29
  • Yes, but right now I'm just trying to get a square selection texture to draw over the tile I am current moused over – Corey Mar 29 '12 at 18:31
  • Yeah that is what I'm trying to do is draw the texture over I was just changing the texture before because I didn't know how to draw it because I didn't know what to use for the rectangle – Corey Mar 29 '12 at 18:32
  • I've added some more code. The draw method will draw `selected.texture`, or whatever texture you want, at the position of the hovered tile. If the mouse is over no tile, the texture won't appear at all. – Msonic Mar 29 '12 at 18:35
  • That works but it is running terribly. Something is killing the performance and it draws the selection diagonally like 3 tiles from where the mouse is. Oh crap I have a camera so I need to get the position based on that right? – Corey Mar 29 '12 at 18:43
  • Indeed, I can't guess what else you have done with this :) fixing the rest of your code is up to you. For the performance issue, how many tiles are you drawing? If you have a very large amount, it may be costly to check if the mouse is inside each tile. – Msonic Mar 29 '12 at 18:49
  • Yeah I think I can get it now I was just mainly confused about the drawing aspect of the selection. I did have 50x50 and just changed it to 17x15 and it is running way better but it is still pretty cpu intensive – Corey Mar 29 '12 at 18:53
  • You should check the other answer if performance is an issue. This answer is gridsize-dependent whereas the other is not. – A-Type Mar 30 '12 at 17:48