/* * JavaEyes - a program that draws eyes that follows the mouse pointer. * October 2003 * * @author Ben Bederson, (c) University of Maryland, Computer Science Department */ import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * The main class that represents the JavaEyes program. */ public class JavaEyes extends JPanel { // Constants to control look of eyes static final int EYE_RADIUS = 40; // The radius of the eye (in pixels) static final int EYE_SPACE = 20; // The space between the two eyes (in pixels) static final int PUPIL_RADIUS = 10; // The radius of the pupil (in pixels) static final Color PUPIL_COLOR = Color.red; // The color of the pupil // Constants to control physics of interaction static final int ATTRACTION = 1; static final int REPULSION = 2; // Variables representing current state of eyes int physics = ATTRACTION; // What kind of physics to use int eyeRadius = EYE_RADIUS; // Current radii of eyes int eyeSpace = EYE_SPACE; // Current space between eyes int pupilRadius = PUPIL_RADIUS; // Current radii of pupils Color pupilColor = PUPIL_COLOR; // Current color of pupils; int leftEyeX, leftEyeY; // Left eye upper-left corner int rightEyeX, rightEyeY; // Right eye upper-left corner int leftPupilX, leftPupilY; // Left pupil upper-left corner int rightPupilX, rightPupilY; // Right pupil upper-left corner int pointerX, pointerY; // Most recent position of pointer public JavaEyes() { setBackground(Color.white); addMouseMotionListener(new EyeListener(this)); // Register for changes in mouse position addComponentListener(new EyeComponentListener(this)); // Register for changes in window geometry // Create a top-level window to put the eyes in JFrame frame = new JFrame("Java Eyes"); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setBounds(100, 100, 400, 300); frame.setContentPane(this); frame.show(); } public void setPhysics(int newPhysics) { if ((newPhysics == ATTRACTION) || (newPhysics == REPULSION)) { physics = newPhysics; computeEyePositions(); repaint(); } } public void setEyeRadius(int newEyeRadius) { if (newEyeRadius > 0) { eyeRadius = newEyeRadius; computeEyePositions(); repaint(); } } public void setEyeSpace(int newEyeSpace) { if (newEyeSpace > 0) { eyeSpace = newEyeSpace; computeEyePositions(); repaint(); } } public void setPupilRadius(int newPupilRadius) { if (newPupilRadius > 0) { pupilRadius = newPupilRadius; computeEyePositions(); repaint(); } } public void setPupilColor(Color newPupilColor) { pupilColor = newPupilColor; repaint(); } /** * This should be called whenever the pointer is moved. * It causes the pupil position to be recomputed, and * triggers repainting of the eyes. * * @param pointerX The X position of the mouse pointer * @param pointerY The Y position of the mouse pointer */ public void setPointerPosition(int newPointerX, int newPointerY) { pointerX = newPointerX; pointerY = newPointerY; computeEyePositions(); repaint(); } /** * Paints the eyes (and pupils) on the screen using values * that have been precomputed. */ public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.black); g.drawArc(leftEyeX, leftEyeY, eyeRadius * 2, eyeRadius * 2, 0, 360); g.drawArc(rightEyeX, rightEyeY, eyeRadius * 2, eyeRadius * 2, 0, 360); g.setColor(pupilColor); g.fillArc(leftPupilX, leftPupilY, pupilRadius * 2, pupilRadius * 2, 0, 360); g.fillArc(rightPupilX, rightPupilY, pupilRadius * 2, pupilRadius * 2, 0, 360); } /** * This is the math part that computes the position of the eyes and the pupils * based on the dimensions of the window, and the position of the pointer. */ void computeEyePositions() { // First compute the center of the eyes based on the window size int leftEyeCtrX = (getWidth() / 2) - eyeRadius - (eyeSpace / 2); int rightEyeCtrX = (getWidth() / 2) + eyeRadius + (eyeSpace / 2); int eyeCtrY = getHeight() / 2; // Then based on the center, compute the left and right sides of each eye leftEyeX = leftEyeCtrX - eyeRadius; leftEyeY = eyeCtrY - eyeRadius; rightEyeX = rightEyeCtrX - eyeRadius; rightEyeY = eyeCtrY - eyeRadius; // Now the tricky part - compute the position of the left pupil // This is calculated by using similar triangles based on the // center of the eye and the pointer position. int pupilDist = (int)(eyeRadius - (pupilRadius * 1.5)); if (physics == REPULSION) { pupilDist *= -1; } int pointerDist = (int)Math.sqrt((pointerX - leftEyeCtrX)*(pointerX - leftEyeCtrX) + (pointerY - eyeCtrY)*(pointerY - eyeCtrY)); if (pointerDist > 5) { leftPupilX = (int)(leftEyeCtrX + pupilDist * (pointerX - leftEyeCtrX) / pointerDist) - pupilRadius; leftPupilY = (int)(eyeCtrY + pupilDist * (pointerY - eyeCtrY) / pointerDist) - pupilRadius; } // And finally compute the position of the right pupil pointerDist = (int)Math.sqrt((pointerX - rightEyeCtrX)*(pointerX - rightEyeCtrX) + (pointerY - eyeCtrY)*(pointerY - eyeCtrY)); if (pointerDist > 5) { rightPupilX = (int)(rightEyeCtrX + pupilDist * (pointerX - rightEyeCtrX) / pointerDist) - pupilRadius; rightPupilY = (int)(eyeCtrY + pupilDist * (pointerY - eyeCtrY) / pointerDist) - pupilRadius; } } public static void main(String[] args) { new JavaEyes(); } } /** * This is a utility class that reports mouse motion back to the eyes. */ class EyeListener extends MouseMotionAdapter { JavaEyes eyes; // Store a reference back to the actual eyes public EyeListener(JavaEyes e) { eyes = e; } /** * Gets notified whenever the mouse moves, and reports changes back to the eyes. */ public void mouseMoved(MouseEvent e) { eyes.setPointerPosition(e.getX(), e.getY()); } } class EyeComponentListener extends ComponentAdapter { JavaEyes eyes; // Store a reference back to the actual eyes public EyeComponentListener(JavaEyes e) { eyes = e; } /** * Gets notified whenever the mouse moves, and reports changes back to the eyes. */ public void componentResized(ComponentEvent e) { eyes.computeEyePositions(); } }