4
\$\begingroup\$

Question copied from the book:

(Game: eye-hand coordination) Write a program that displays a circle of radius 10 pixels filled with a random color at a random location on a panel, as shown in Figure 16.28c. When you click the circle, it disappears and a new randomcolor circle is displayed at another random location. After twenty circles are clicked, display the time spent in the panel, as shown in Figure 16.28d.

My solution:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class EyeHandCoordination extends JFrame {
    private final int CIRCLE_RADIUS = 10;
    private final int TOTAL_CIRCLES = 20;
    private RandomCirclePanel panel = new RandomCirclePanel();

    public EyeHandCoordination() {
        add(panel);
    }

    public static void main(String[] args) {
        EyeHandCoordination frame = new EyeHandCoordination();
        frame.setTitle("EyeHandCoordination");
        frame.setSize(300, 300);
        frame.setLocationRelativeTo(null); // Center the frame
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }



    private class RandomCirclePanel extends JPanel {
        private long startTime;
        private long endTime;

        private int circleX = 0;
        private int circleY = 0;

        private int currentCircle = 0;

        public RandomCirclePanel() {
            startTime = System.currentTimeMillis();

            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    // Check if in circle
                    if (inCircle(e.getX(), e.getY()) && currentCircle < TOTAL_CIRCLES) {
                        currentCircle++;
                        repaint();
                    }
                }
            });
        }

        /** Display circle at a random location **/
        private void changeCircleLocation() {
            circleX = (int)(Math.random() * (getWidth() - CIRCLE_RADIUS * 2)); 
            circleY = (int)(Math.random() * (getHeight() - CIRCLE_RADIUS * 2));
        }

        /** Check if inCircle **/
        public boolean inCircle(int mouseX, int mouseY) {
            if (distanceFromCenterOfCircle(mouseX, mouseY) <= CIRCLE_RADIUS) {
                return true;
            }

            return false;
        }

        private int distanceFromCenterOfCircle(int x, int y) {
            int centerX = circleX + CIRCLE_RADIUS;
            int centerY = circleY + CIRCLE_RADIUS;

            return (int)(Math.sqrt((centerX - x) * (centerX - x) + (centerY - y) * (centerY - y)));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int width = getWidth();
            int height = getHeight();

            changeCircleLocation();

            if (currentCircle >= TOTAL_CIRCLES) {
                g.setColor(Color.BLACK);
                endTime = System.currentTimeMillis();
                FontMetrics fm = g.getFontMetrics();
                String s = "Time spent: " + ((endTime - startTime) / 1000.0) + " seconds";
                g.drawString(s, width / 2 - fm.stringWidth(s) / 2, height / 2 - fm.getAscent());
            }
            else {
                g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256)));
                g.fillOval(circleX, circleY, CIRCLE_RADIUS * 2, CIRCLE_RADIUS * 2);
            }
        }
    }
}
\$\endgroup\$
2
\$\begingroup\$
public boolean inCircle(int mouseX, int mouseY) {
    if (distanceFromCenterOfCircle(mouseX, mouseY) <= CIRCLE_RADIUS) {
        return true;
    }

    return false;
}

Can be

public boolean inCircle(int mouseX, int mouseY) {
    return distanceFromCenterOfCircle(mouseX, mouseY) <= CIRCLE_RADIUS;
}

(int)(Math.random() * (getWidth() - CIRCLE_RADIUS * 2));

g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256)));

Looks like you could benefit from a function that takes an integer as maximum value... and then returns an integer between 0 and max minus 1.

Which does exist - you'd simply create a new instance of Random and then call randomInstance.nextInt(maxValue).


Lastly, I think you would be better off by renaming the currentCircle variable to amountOfCirclesDisplayed because that's what it really is. currentCircle seems to point to the idea that somewhere, you have a list of circles, and right now, you're working on 1 specific circle. But that's not true, because you HAVE no list of circles and all that really matters is how many you've displayed so far.

\$\endgroup\$
2
  • \$\begingroup\$ Regarding the first point: I'm not quite sure why I wrote it that way lol. Question regarding the second point: I read somewhere in my book that it generally takes a lot of resources to create objects; would be more efficient to use Random anyway in this case? And yes, now I realize after you mentioned it that currentCircle is not a good name for that field haha. Thanks for your thorough reply!! \$\endgroup\$ – Legate Aug 23 '16 at 2:03
  • 1
    \$\begingroup\$ @Legate that's premature optimization, you'd benefit more from the readability than the speed \$\endgroup\$ – Pimgd Aug 23 '16 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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