import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.util.Vector; /** Bounce circles around on the screen, using * double buffering for speed and to avoid problems * with overlapping circles. Overrides update to * to avoid flicker problems. */ public class DoubleBufferBounce extends Applet implements Runnable, ActionListener { private Vector circles; private int width, height; private Image offScreenImage; private Graphics offScreenGraphics; private Button startButton, stopButton; private Thread animationThread = null; public void init() { setBackground(Color.white); width = getSize().width; height = getSize().height; offScreenImage = createImage(width, height); offScreenGraphics = offScreenImage.getGraphics(); // Automatic in some systems, not in others offScreenGraphics.setColor(Color.black); circles = new Vector(); startButton = new Button("Start a circle"); startButton.addActionListener(this); add(startButton); stopButton = new Button("Stop all circles"); stopButton.addActionListener(this); add(stopButton); } //---------------------------------------------------- /** When the "start" button is pressed, start the * animation thread if it is not already started. * Either way, add a circle to the Vector of * circles that are being bounced. * * When the "stop" button is pressed, stop * the thread and clear the Vector of circles. */ public void actionPerformed(ActionEvent event) { if (event.getSource() == startButton) { if (circles.size() == 0) { animationThread = new Thread(this); animationThread.start(); } int radius = 25; int x = radius + randomInt(width - 2 * radius); int y = radius + randomInt(height - 2 * radius); int deltaX = 1 + randomInt(10); int deltaY = 1 + randomInt(10); circles.addElement(new MovingCircle(x, y, radius, deltaX, deltaY)); repaint(); } else if (event.getSource() == stopButton) { if (animationThread != null) { animationThread = null; circles.removeAllElements(); } } } //---------------------------------------------------- /** Each time around the loop, move each circle * based on its current position and deltaX/deltaY * values. These values reverse when the circles * reach the edge of the window. */ public void run() { MovingCircle circle; Thread myThread = Thread.currentThread(); // Really while thread not stopped while(animationThread==myThread) { for(int j=0; j<circles.size(); j++) { circle = (MovingCircle)circles.elementAt(j); circle.move(width, height); } repaint(); pause(100); } } //---------------------------------------------------- /** Skip the usual screen-clearing step of update * so that there is no "flicker" between each * drawing step. */ public void update(Graphics g) { paint(g); } //---------------------------------------------------- /** Clear the offscreen pixmap, draw each circle * onto it, then draw that pixmap onto the * applet window. */ public void paint(Graphics g) { offScreenGraphics.clearRect(0, 0, width, height); MovingCircle circle; for(int i=0; i<circles.size(); i++) { circle = (MovingCircle)circles.elementAt(i); circle.draw(offScreenGraphics); } g.drawImage(offScreenImage, 0, 0, this); } //---------------------------------------------------- // Returns an int from 0 to max (inclusive), // yielding max + 1 possible values. private int randomInt(int max) { double x = Math.floor((double)(max + 1) * Math.random()); return((int)(Math.round(x))); } //---------------------------------------------------- // Sleep for the specified amount of time. private void pause(int milliseconds) { try { Thread.sleep((long)milliseconds); } catch(InterruptedException ie) {} } } |
© 1996-99 Marty Hall, 1999 Lawrence M. Brown