/*********************************************************************** * Tom Kelliher * CS 245 * Bounce2.java * * This applet is a first pass at controlling a bouncing ball via a * moded start/stop button. * * Extensions to try: * 1) Have the start/stop button control three balls, of different * colors, rather than one ball. * 2) Add a button to add additional bouncing balls (up to 100, * total). Each press of this button adds one ball. All balls * should be stopped and removed when the stop button is pressed. * The start button continues to start a single bouncing ball. * 3) Animate the balls in the X- and Y-dimensions. * * Comments in the following point out departures from Bounce1.java. ***********************************************************************/ import java.applet.*; import java.awt.*; import java.awt.event.*; public class Bounce2 extends Applet implements ActionListener { private Canvas display = new Canvas(); private Button startStop = new Button("Start"); private Ball ball = null; public void init() { setLayout(new BorderLayout()); add("South", startStop); add("Center", display); startStop.addActionListener(this); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Start")) { startStop.setLabel("Stop"); ball = new Ball(display, Color.red); /* We no longer animate the ball here. Instead, we start its * thread. */ ball.start(); } else { startStop.setLabel("Start"); ball.finish(); // Terminate the ball's thread. } } } /*********************************************************************** * class Ball --- This class extends the Thread class, therefore it must * have a run() method. ***********************************************************************/ class Ball extends Thread { private Canvas theCanvas; private Color color; private int x, y; private double velocity; private boolean done = false; // Is thead done executing? public Ball(Canvas c, Color co) { theCanvas = c; color = co; x = c.getWidth() / 2; y = (int) (10 + (c.getHeight() - 20) * Math.random()); velocity = 0.6 + Math.round(2.5 * Math.random()); } /*********************************************************************** * public void run() --- As its last action, the default start() method * calls run(). This is where we use the new thread to animate the * ball. ***********************************************************************/ public void run() { draw(color); while (!done) { move(); /* Try/catch pair necessary as during sleep() the checked * InterruptedException may occur and must be handled. * Note the empty handler in the catch clause. */ try { /* Thread sleeps for 10 ms., yielding control to another * thread. This efficiently replaces our spin-loop. */ sleep(10); } catch (InterruptedException e) { } } draw(Color.white); // Clean up by de-rendering the ball. } private void draw(Color c) { Graphics g = theCanvas.getGraphics(); g.setColor(c); g.fillOval(x, y, 10, 10); g.dispose(); } private void move() { draw(Color.white); if (x <= 0 || x >= theCanvas.getWidth()) velocity = -velocity; x = (int) (Math.round(x + velocity)); draw(color); } /*********************************************************************** * public void finish() --- Set the done flag, ultimately causing the * thread to complete. * * Note: Thread.stop() is deprecated. Do not use it. It does not allow * a thread to clean up after itself. ***********************************************************************/ public void finish() { done = true; } }