Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm making a simple tile-map system in LWJGL, and I'm trying to figure out how to detect if the mouse is clicking inside of a tile. So far no matter where I click it's always the same tile that is shown.

Code:

int blockWidth = 100;
int blockHeight = 100;

List<Tile> tiles = new ArrayList<Tile>();

private void addTiles(){
    for(int i = 0; i < ((Display.getHeight() / blockHeight) * (Display.getWidth() / blockWidth)); i++)
        tiles.add(new Tile(10,10,blockWidth,blockHeight, i));
}

//...

if(Mouse.isButtonDown(0)){
            System.out.println("Mouse clicked at (" + Mouse.getX() + ", " + Mouse.getY() + ")");
            for(Tile tile : tiles){
                if(tile.inBounds(Mouse.getX(), Mouse.getY())){
                    tile.highlight();
                    System.out.println("Box clicked at (" + Mouse.getX() + ", " + Mouse.getY() + ").");
                    break;
                }
            }
}

the inBounds method:

public boolean inBounds(int x, int y){
    Rectangle bounds = new Rectangle();
    bounds.setBounds(x, y, width, height);
    if(bounds.intersects(x,y,1,1)){
        System.out.println("Tile " + num + " clicked. X/Y val is (" + this.x + "," + this.y + ")");
        return true;
    }else{
        return false;
    }

}
share|improve this question
add comment

2 Answers 2

up vote 3 down vote accepted

The x and y you use here:

bounds.setBounds(x, y, width, height);

are the parameters x, y that are being passed into the method.

I am assuming that there is also an x and y in your Tile class. So you either need to rename the parameters or use this. in front of your variables.

public boolean inBounds(int x, int y){
    Rectangle bounds = new Rectangle();
    bounds.setBounds(this.x, this.y, width, height); // change here
    if(bounds.intersects(x,y,1,1)){
        System.out.println("Tile " + num + " clicked. X/Y val is (" + this.x + "," + this.y + ")");
        return true;
    }else{
        return false;
    }
}
share|improve this answer
    
"this" is very tricky! A very common mistake. One that I am prone to as well even after as many years as I have been coding. The primary way I use to combat this problem (usually quite effectively), is to always have "the" in front of parameters passed to a function. For example, if I were to write inBounds, the parameter names would be theX and theY. Helps me anyway. Might help others as well to have a naming convention to help avoid this all too common issue. –  PlayDeezGames Feb 29 '12 at 1:35
    
@PlayDeezGames - I've gotten into the habit of naming all my class fields starting with an underscore (_). I've also seen the use of m_ for fields (the "m" stands for "member" because, as you can see in the docs, fields implement the Member interface). Personally, I don't really like the m_ but regardless, naming and scope are very important when programming. :) –  Richard Marskell - Drackir Feb 29 '12 at 3:18
add comment

You can avoid the potentially O(N*M) containemt checks by simply calculating the tile's array index in O(1) time:

int pixelCoordToIndex(int x, int y)
{
    return ((y / tileHeight) * numTilesX) + (x / tileWidth);
}


Your code is then reduced to:

System.out.println("Tile " + pixelCoordToIndex(x, y) + " clicked. X/Y val is (" + x + "," + y + ")");


This decouples the performance of containment checks from the map's extents, saving millions of unnecessary checks on moderately large maps.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.