import java.awt.*; import java.applet.Applet; import java.awt.event.*; class Ball { int x = 7, xChange = 7; int y = 2, yChange = 2; int diameter = 10; Color color = Color.RED; Ball() { } Ball(int x, int y, int xChange, int yChange, int diameter, Color color) { this.x = x; this.y = y; this.xChange = xChange; this.yChange = yChange; this.diameter = diameter; this.color = color; } } class Bounds { int LeftX = 50, RightX = 150; int TopY = 50, BottomY = 150; } public class BallBox6 extends Applet implements Runnable, MouseListener { int numBalls = 5; Ball [] balls; Bounds box; // Next two lines allow for "friendly" animation Thread t = null; boolean threadSuspended = true; public void init() { box = new Bounds(); balls = new Ball[numBalls]; balls[0] = new Ball(); balls[1] = new Ball(7, 2, 3, 5, 12, Color.GREEN); balls[2] = new Ball(7, 2, 4, -1, 8, Color.BLUE); balls[3] = new Ball(7, 2, 5, 2, 9, Color.CYAN); balls[4] = new Ball(7, 2, 3, -4, 11, Color.MAGENTA); addMouseListener(this); } private void eraseBall(Graphics g, Ball ball) { g.fillOval(ball.x + box.LeftX, ball.y + box.TopY, ball.diameter, ball.diameter); } private void moveAndDrawBall(Graphics g, Ball ball) { int margin = ball.diameter; int width = box.RightX - box.LeftX - margin; int height = box.BottomY - box.TopY - margin; if (ball.x <= 0) ball.xChange = -ball.xChange; if (ball.x >= width) ball.xChange = -ball.xChange; if (ball.y <= 0) ball.yChange = -ball.yChange; if (ball.y >= height) ball.yChange = -ball.yChange; ball.x = ball.x + ball.xChange; ball.y = ball.y + ball.yChange; g.setColor(ball.color); g.fillOval(ball.x + box.LeftX, ball.y + box.TopY, ball.diameter, ball.diameter); } public void paint(Graphics g) { if (!threadSuspended) { g.drawString("Click to Stop", box.LeftX, box.TopY - 10); } else { g.drawString("Click to Start", box.LeftX, box.TopY - 10); } g.drawRect(box.LeftX, box.TopY, box.RightX - box.LeftX, box.BottomY - box.TopY); Color backgroundColor = getBackground(); g.setColor(backgroundColor); for (int i = 0; i < numBalls; i++) { eraseBall(g, balls[i]); } for (int i = 0; i < numBalls; i++) { moveAndDrawBall(g, balls[i]); } } /* * The following routines destroy(), start(), stop(), run() are needed * to manage the thread which handles the animation. You don't need to * understand them (threads are in chapter 25). If you wanted to put int * a different animation you would change paint() and updateMyAnim(); */ // Executed when the applet is destroyed. public void destroy() { } // Executed after the applet is created; and also whenever // the browser returns to the page containing the applet. // This is boilerplate - don't change it! public void start() { if ( t == null ) { t = new Thread( this ); threadSuspended = false; t.start(); } else { if ( threadSuspended ) { threadSuspended = false; synchronized( this ) { notify(); } } } } // Executed whenever the browser leaves the page containing the applet. public void stop() { threadSuspended = true; } // Executed within the thread that this applet created. // more boilerplate. public void run() { try { while (true) { // Here's where the thread does some work // In BallBox all updating actually happens in paint so we // don't have this routine. // updateMyAnim(); // Now the thread checks to see if it should suspend itself if ( threadSuspended ) { synchronized( this ) { while ( threadSuspended ) { wait(); } } } // the call to repaint causes the window system to call our paint. repaint(); t.sleep( 50 ); // interval given in milliseconds to sleep // larger number - slower animation // smaller number - faster animation } } catch (InterruptedException e) { } } // Mouse listener routines to allow for starting / stopping of animation public void mouseClicked(MouseEvent event) { if (!threadSuspended) { stop(); repaint(); } else { start(); } } public void mouseReleased(MouseEvent event) { } public void mousePressed(MouseEvent event) { } public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } }