Search code examples
javauser-interfaceanimationjavafxgame-physics

JavaFX checking collision between animated shapes on pane - multiple collisions


I am making a simple game with JavaFX, where a ball bounces around the screen after being released from the bottom (via a button). When the ball is bouncing around the pane, if it hits a Rectangle it changes its color to blue.

I am attempting to add a method called checkBounds to keep track of when the ball (a Circle) hits the Rectangle. As soon as the ball comes into contact with the rectangle, the score should increase by 10. The scoring mechanism works, but it continues to increment with each frame that the ball takes through the Rectangle, instead of only incrementing once when it enters. (eg. It should only go up by 10 one time, not continue going up by 10 the whole time the ball passes through). I callcheckBounds() 3 times in my timeline loop to check each rectangle on each loop iteration.

checkBounds(ball, gameSquare); checkBounds(ball, gameSquare2); checkBounds(ball, gameSquare3);

How would I fix this logic error? I've attempted several different options, but none seem to work.

private void checkBounds(Shape block, Rectangle rect) {

    boolean collisionDetected = false;

    Shape intersect = Shape.intersect(block, rect);

    if (intersect.getBoundsInLocal().getWidth() != -1) {
        collisionDetected = true;
    }

    if (collisionDetected) {
        score.setText(Integer.toString(currentScore.getCurrentValue()));
        currentScore.incrementBy(10);
        rect.setFill(Color.BLUE);
    }
}

Solution

  • I believe what you want to detect is the state change of your collisionDetected from false to true. One way to do this is to keep the state of the previous value as a member variable for each collision object. To do this, we need some identifying id for the rectangle, so you may want to pass in the id into the checkBounds method:

    private void checkBounds(Shape block, Rectangle rect, int id) {
    

    we also need to create a member variable to store the states:

    private HashMap<Integer,Boolean> previousCollisionStateMap = new HashMap<>();
    

    and then inside your checkBounds code, you can modify the condition to check for changes

    Boolean prevState = previousCollisionStateMap.get(id);
    if (prevState == null) {  // this is just to initialize value
        prevState = false;
        previousCollisionStateMap.put(id,false);
    }
    
    if (!prevState && collisionDetected) {
        score.setText(Integer.toString(currentScore.getCurrentValue()));
        currentScore.incrementBy(10);
        rect.setFill(Color.BLUE);
    }
    

    and don't forget to update the state at the end

    previousCollisionStateMap.put(id,collisionDetected);