| In the Chapter 8: 
              Java: Animations we presented examples of animations with Swing 
              components but using the standard drawing tools in the Graphics 
              class. Here we remake the DropApplet 
              animation example with the more capable Java 2D drawing classes. 
             As before, the Drop2DApplet 
              program below illustrates a simple simulation of a bouncing ball. 
              The applet creates a thread to direct the drawing of the frames 
              of the animation as the ball falls and bounces on the floor and 
              gradually comes to a rest. The interface consists of a subclass 
              of JPanel 
              called Drop2DApplet 
              and a button to initiate a new drop of the ball. Drop2DApplet 
              displays the ball and calculates its position.  The applet implements Runnable 
              and in the start() 
              method it creates a thread to which it passes a reference to itself. 
              The applet's run() 
              method first does some initialization and then enters a loop that 
              draws each frame of the animation. The loop begins with a 25 millisecond 
              pause using the static sleep() 
              method in the Thread 
              class. Then the Drop2DApplet 
              is told to paint the next frame.  If the drop is done, the process jumps from the loop and exits 
              the run() 
              method, thus killing this thread.  Note how the antialiasing makes the ball much more smoothly round 
              than with the AWT version.  
              
                 
                  |  |   
                  |  
                      import 
                        javax.swing.*;import java.awt.*;
 import java.awt.event.*;
 
 /**
 * This applet implements Runnable and uses 
                        a thread
 * to create a simple dropped ball demonstration.
 **/
 public class Drop2DApplet extends JApplet
 implements 
                        Runnable, ActionListener{
 // Will use thread reference as a flag
 Thread fThread;
 Drop2DPanel fDropPanel;
 JButton fDropButton;
 
 /** Build the interface. **/
 public void init () {
 Container content_pane = getContentPane 
                        ();
 content_pane.setLayout (new BorderLayout 
                        ());
 
 // Create an instance of DropPanel
 fDropPanel = new Drop2DPanel ();
 // Add the DropPanel to the content 
                        pane.
 content_pane.add ("Center",fDropPanel);
 
 // Create a button and add it
 fDropButton = new JButton ("Drop");
 fDropButton.addActionListener 
                        (this);
 content_pane.add ("South",fDropButton);
 
 } // init
 
 /** Start when browser is loaded or button 
                        pushed. **/
 public void start () {
 // If the thread reference not 
                        null then a
 // thread is already running. 
                        Otherwise, create
 // a thread and start it.
 if (fThread == null){
 fThread 
                        = new Thread (this);
 fThread.start 
                        ();
 }
 } // start
 
 /** Applet's stop method used to stop thread.**/
 public void stop () {
 // Setting thread to null will 
                        cause loop in
 // run () to finish and kill 
                        the thread.
 fThread = null;
 }
 
 /** Button command. **/
 public void actionPerformed (ActionEvent ae){
 if (fDropPanel.isDone ()) start 
                        ();
 }
 
 /** The thread loops to draw each frame of 
                        drop.**/
 public void run () {
 // Disable button during drop
 fDropButton.setEnabled (false);
 
 // Initialize the ball for the 
                        drop.
 fDropPanel.reset ();
 
 // Loop through animation frames
 while ( fThread != null){
 // Sleep 25msecs 
                        between frames
 try{ Thread.sleep 
                        (25);
 } catch  (InterruptedException 
                        e) { }
 // Repaint drop panel 
                        for each new frame
 fDropPanel.repaint 
                        ();
 if (fDropPanel.isDone 
                        ()) fThread = null;
 }
 // Enable button for another drop
 fDropButton.setEnabled (true);
 } // run
 } // class DropApplet
 |   
                  | import 
                    javax.swing.*; import java.awt.*;
 import java.awt.geom.*;
 
 /** This JPanel subclass animates the dropping of a ball.**/
 public class Drop2DPanel extends JPanel{
 
 // Parameters for the drop
 double fY = 0.0, fVy = 0.0;
 // Conversion factor from cm to pixels.
 double fYConvert = 0.0;
 double fXPixel = 0.0, fYPixel = 0.0;
 double fRadius = 0.0, fDiam = 0.0;
 // starting point for ball in cm
 double fY0 = 1000.0;
 // Frame dimensions.
 double fFrameHt, fFrameWd;
 // Flag for drop status
 boolean fDropDone = false;
 
 Ellipse2D fBall;
 
 /** Reset parameters for a new drop. **/
 void reset(){
 fFrameHt = getHeight();
 fFrameWd = getWidth();
 
 fXPixel = getWidth()/2;
 fY = fY0; fVy = 0;
 
 // Conversion factor from cm to pixels
 // Start the ball about 20% from the 
                    top
 // of the frame
 fYConvert = fFrameHt / (1.2 * fY0);
 
 // Choose a size for the ball relative 
                    to the
 // height in pixel units.
 fRadius = (int)((0.1 * fY0) * fYConvert);
 fDiam = 2 * fRadius;
 
 fBall = new Ellipse2D.Double(fXPixel-fRadius,
 fYPixel-fRadius,
 fDiam,fDiam);
 setBackground(Color.WHITE);
 fDropDone=false;
 } // reset
 
 /** Draw the ball at its current position. **/
 public void paintComponent (Graphics g){
 super.paintComponent(g);
 Graphics2D g2 = (Graphics2D)g;
 // Antialiasing for smooth surfaces.
 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 RenderingHints.VALUE_ANTIALIAS_ON);
 
 // Determine position after this time 
                    increement
 calcPosition ();
 // Move the ball.
 fBall.setFrame(fXPixel-fRadius,
 fYPixel-fRadius,
 fDiam,fDiam);
 // Want a solid red ball
 g2.setColor (Color.RED);
 g2.fill(fBall);
 
 // Now draw the ball.
 g2.draw (fBall);
 } // paintComponent
 
 /** Calculate the ball position in the next frame. 
                    **/
 void calcPosition () {
 // Increment by 10 millseconds per 
                    frame
 double dt = 0.025;
 
 // Calculate position and velocity 
                    at each step
 fY = fY + fVy * dt - 490.* dt * dt;
 fVy = fVy  -  980.0 
                    * dt;
 
 // Convert to the pixel coordinates
 fYPixel = fFrameHt - (int)(fY * fYConvert);
 
 // Reverse direction when ball hits 
                    bottom.
 if ((fYPixel + fRadius) >= (fFrameHt-1)) 
                    {
 fVy = Math.abs 
                    (fVy);
 // Subtract 
                    friction loss
 fVy -= 0.1*fVy;
 // Stop when 
                    speed at bottom drops below arbitrary limit
 if (fVy < 
                    15.0) {
 fDropDone=true;
 }
 }
 } // clacPosition
 
 /** Provide a flag on drop status. **/
 public boolean isDone () {
 return fDropDone;
 }
 
 } // class DropPanel
 |      Latest update: Nov. 5, 2004 |