Search code examples
javatimertaskawtrobot

Why can't I get my Red Ball to Stop on the Blue Box using robot.getPixelColor?


Title. GUI looks like the following: Ball Puzzle GUI

The code below is for my Timer Task responsible for controlling the downwards movement of the ball, called by:

timer.scheduleAtFixedRate(moveDown, 0, 20);

Whenever an arrow key is pressed, the ball is supposed to continuously move in that direction until it encounters a square. I know I'm using .cancel() right now but I intend to fix that with a temporary pause of the TimerTask.

While not adding anything to the X or Y values, the ball never stops. (I should mention when it reaches the bottom it is looped back to the top) The outputted colors seem to change when not change X or Y values. For instance, at (0,360) the first time around, the outputted color is (208,208,208) while the next time around at (0,360) the outputted color is (240,240,240).

When adding what I thought would stop it right on the edge of the box, Y + 51, it still doesn't stop. The only color detected is (208,208,208) which is a grey color.

If I added both Y + 51 and X + 25, the ball still never stops, and only grey is outputted. Note I've changed the velocity to 1 and it makes no difference.

Now, by some stroke of luck I've found that if I add 80 to the Y and 25 to the X, it will stop right on the edge of the box.

I also found that if I add 25 to the Y and 25 to the X for the TimerTask responsible for moving the ball upwards (velocity is negative) the ball will stop 1 pixel away from the edge of the box.

   public void run() {
      try {
            Robot robot = new Robot();
            int y = ball.positionY + 80;
            int x = ball.positionX + 25;

            System.out.println(ball.positionX);
            System.out.println(ball.positionY);

            color = robot.getPixelColor(x, y);

            System.out.println("Red   = " + color.getRed());
            System.out.println("Green = " + color.getGreen());
            System.out.println("Blue  = " + color.getBlue());

        } catch (AWTException e) {

            e.printStackTrace();

        }

        if((color.getRed() == 0) && (color.getGreen() == 0) && (color.getBlue() == 255)){

            moveDown.cancel();
            moving = false;

        }

        else{

        ball.positionY += 5;

        if (ball.positionY > 670) {

            ball.positionY = 0;

        }
        }

        ball.repaint();
    }

Does anyone know what the heck is actually going on? I haven't been able to figure out the right/left directions yet as there doesn't seem to be a pattern.


Solution

  • Robot is not a reliable way to detect your squares. Double buffering may mean that your pixels are not actually showing.

    Since your own code is drawing the squares, keep the coordinates of those squares in a private field, and use them to check for collision instead of checking pixel colors:

    private final Collection<Rectangle> squares = new ArrayList<>();
    
    // ...
    
        if (squares.stream().anyMatch(sq -> sq.contains(x, y))) {
            moveDown.cancel();
            moving = false;
        } else {
            ball.positionY += 5;
            if (ball.positionY > 670) {
                ball.positionY = 0;
            }
        }
    

    Also be aware that Swing is not safe for use by multiple threads. You should be using javax.swing.Timer instead of java.util.Timer, since it properly executes its tasks in the AWT event dispatch thread.