• Advertisement
Sign in to follow this  

[java] Detect collision with object using Binary Search fails

This topic is 2768 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello

I am currently creating a Swing application & I am trying to detect whether a mouse has clicked within a region(rectangle) on a JPanel.

I am making a 'Game of Nim' game, where I draw piles of matches(view picture because its more clear) onto a JPanel. I have a mouse listener to tell me when the JPanel has been clicked. This is when I use my binary search to find which(if any) match has been left clicked, then I remove that match from the pile.

My problem:
Is that my current algorithm keeps telling me that NO MATCH has been selected EVEN when my mouse has left clicked a match.

** ugh, I give up trying to make the pic appear lol **
But I really encourage u to view the pic as it makes understanding my pile/match layout & where their x,y coords begin ALOT clearer.

[image]http://img59.imageshack.us/img59/6950/matcheg.jpg[/image]


I know there is something wrong with my Binary search or collision functions, but after hours of going over it I cant find whats wrong.

Can you help me figure out why my functions always tell me that no match has been selected even when one has been selected?


I have made a simple algorithm to figure out what match has been selected:
- I have a vector of Piles (each pile contains 10 matches initially)
- I use a binary search to find if the mouse point lies within any piles region (according to the x value) - findSelectedMatchEffic();
- If the mouse lies within a pile's region; I use another binary search to find which match (within that pile) has been selected(collides with the mouse) - findMatch();


My code:




/**
Post: Find which Match has been selected by the users cursor
& return its index & its parent Pile's index as a
SelectedObjectInfo object
This function utilises a binary search for speed &
efficiency
*/

public SelectedObjectInfo findSelectedMatchEffic( int mouseX, int mouseY )
{
int mid;
int begin = 0;
int end = piles.size() - 1;


if ( mouseX < piles.elementAt( 0 ).x )
{
return null;
}
if ( mouseX > (piles.elementAt( end - 1 ).x + piles.elementAt( end - 1 ).width) )
{
return null;
}


while ( begin <= end )
{

mid = (begin + end) / 2;
Pile selPile = piles.elementAt( mid );

if ( selPile.mouseCollision( mouseX, mouseY ))
{
int matchIndex = findMatch( selPile, mouseX, mouseY );

if ( matchIndex != -1 )
{
return ( new SelectedObjectInfo( mid, matchIndex ));
}
else break;
}
else if ( mouseX < selPile.x )
{
end = mid - 1;
}
else if ( mouseX > (selPile.x + selPile.width) )
{
begin = mid + 1;
}

}

return null;
}


/**
Post: Find which Match has been selected by the users cursor
& return its index
This function utilises a binary search for speed &
efficiency
*/

public int findMatch( Pile selPile, int mouseX, int mouseY )
{

int mid;
int begin = 0;
int end = selPile.size() - 1;


while ( begin <= end )
{

mid = (begin + end) / 2;


if ( selPile.at( mid ).mouseCollision( mouseX, mouseY ) )
{
return mid;
}
else if ( mouseY < selPile.at( mid ).y )
{
end = mid - 1;
}
else if ( mouseY > (selPile.at( mid ).y + selPile.at( mid ).height) )
{
begin = mid + 1;
}

}

return -1;
}

}


/**
Member Function of Class Pile:
Post: Returns true if mouse cursor lies within this piles's regions
,ie, returns true if the user has clicked this pile with the mouse
*/

public boolean mouseCollision( int mouseX, int mouseY )
{

// Debugging
System.out.printf("x = %s y = %s width = %s height = %s \n", x,y,width,height);
System.out.printf("LeftPoint (%s,%s) RightPoint (%s,%s) \n", x,y,x-width,y-height);

if ( mouseX >= x && mouseX <= (x+width) && mouseY >= (y-height) && mouseY <= y )
{
return true;
}
else return false;

}



/**
Member Function of Class Match:
Post: Returns true if mouse cursor lies within this matches regions
,ie, returns true if the user has clicked this match with the mouse
*/

public boolean mouseCollision( int mouseX, int mouseY )
{

if ( mouseX >= x && mouseX <= (x+width) && mouseY >= y && mouseY <= (y+height) )
{
return true;
}
else return false;

}









I really hope someone can give me some advice on where my function fails :)

Share this post


Link to post
Share on other sites
Advertisement
Without seeing some more code this is a guess... :)

But in the "findSelectedMatchEffic(...)" method the coordinates origin is bottom-left.

In the "findMatch(...)" method it's top-left.

Do you account for this when rendering the matches?
Otherwise the bounding box could be different to where you see the image.


If not the solution, try to find where it's failling:
Check you're recieving an intial mouse event from the JPanel.
Check it's invoking your code.
Check if it detects you've clicked a pile.
Check if it detects you've clicked a match.

Share this post


Link to post
Share on other sites
findSelectedMatchEffic is wrong:

if (mouseX > (piles.elementAt(end - 1).x + piles.elementAt(end - 1).width)) {
return null;
}


should be

if (mouseX > (piles.elementAt(end).x + piles.elementAt(end).width)) {
return null;
}



Other thoughts:

Why are you still using a Vector?
Why don't you use a List?
If you want to use binary search, a SortedSet would be even better.
Do you know java.util.Collections static methods?

I would separate Pile and Match from their visual representation (MVC, MVP).

Anyway, int findMatch(Pile selPile, int mouseX, int mouseY) should be a method in Pile (or a method in PileView, depending whether you change your approach or not) like int findMatch(int mouseX, int mouseY)

comparisons like mouseX >= x && mouseX <= (x+width) can be read easier as x <= mouseX && mouseX <= (x+width). do you know what I mean?

I would even create a couple of privates boolean xCollision(int mouseX) and boolean yCollision(int mouseY) and then mouseCollision becomes:

public boolean mouseCollision( int mouseX, int mouseY ) {
return xCollision(mouseX) && yCollision(mouseY);
}



This is really ugly:

boolean function() {
if(condition) {
return true;
} else {
return false;
}
}


IMHO this is much clear:

boolean function() {
return condition;
}



Can you redo your program without exposing x, y, width and height?
And I don't mean changing them by getters and setters.
I think if you make that effort your program will evolve to a better form.

Don't do this:
// Debugging
System.out.printf("foo = %s\n", foo);
Create a debug/log function instead.
You can begin with something like:

class Debug {
static void debug(String format, Object ... args) {
System.out.printf(format, args);
}
}


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement