---- Bouncing Ball Applet ----



//        ****    The Bouncing Ball Applet *****
//    ***** This applet by  M. Gallant    4/26/96  ******


import java.awt.*;
public class bounce extends java.applet.Applet implements Runnable {
    Image offIm;
    Graphics offGr;
    Thread runner;
    Color fgnd = Color.black, bgnd;
    Font f = new Font("TimesRoman", Font.PLAIN, 12);
    FontMetrics fmet = getFontMetrics(f) ;
    int  tPause, xBall, ballDiam, ballRad, wApp, hApp;
    int x, bounce, vx, tTotal ;
    final double G = 9.8 ;      // G in m/sec^2 
    double  con, ymax, ymax0,  gb2 , g2, vmax ;
    double  y, t, tb0, dt, tn, hn, tt, scale ; 
    boolean Multi ;
    TextField tf1, tf2; 
    Label lb1, lb2 ;
 public void init() {                    
           setForeground(fgnd);
           bgnd=getBackground();
           bgnd = new Color(136,187,221) ;
           wApp  = this.size().width;
           hApp  = this.size().height -50;              
           offIm = createImage(wApp, hApp);
           offGr = offIm.getGraphics();           
           offGr.setColor(Color.red) ;
           setFont(f);
       Multi = false;
       ymax0 = 50;                      // initial real height in meters.
       x = 0;   // note that y and ymax are measured from top down.             
       y = 0.0;
       gb2 = G/2.0 ;
       g2 = 2.0*G ;
       dt = 0.10 ;                         //time between ball updates in seconds.
       tPause =  (int)(1000*dt) ;          // pause in ms.
       ballRad = 3;
       ballDiam = 2*ballRad;                // ball diameter in pixels.
       vx = 2;                              // lateral velocity in pixels per calculate interval.
    setLayout(new FlowLayout());
    add (new Label("Height (m)")) ;
    tf1 = new TextField(String.valueOf(ymax0) ,5) ;
    add (tf1) ;
    add (new Button("Multi") ) ;
    add (new Button("Time")) ;
    lb1 = new Label("Time =     sec") ;    
    add (lb1) ;
    lb2 = new Label("             ");
    add (lb2) ; 
} 


public Insets insets(){
 return new Insets(hApp+5,5,5,5);
 }


 public void start()  {
     if (runner == null)  {
     runner = new Thread(this);
     runner.start();
    }
 }

public void stop() {
   if (runner != null) {
        runner.stop();
        runner = null;
     }
 }

 
 public void pause(int time) {
            try { Thread.sleep(time);}  // wait for time milliseconds.
            catch (InterruptedException e) { }
         }



  public void run() {
      con = Math.sqrt(ymax0/G) ;    
      tt = Math.sqrt(2.0*ymax0/G)*(3 + 2.0*Math.sqrt(2.0) ) ; // time for all bounces.
      scale = hApp/ymax0 ;    //  scale to Applet vertical size.  
   // System.out.println("Total time : "+tt) ;
      lb2.setText("Tf: "+ .1*(int)(10*tt) + " sec") ;
         tb0 =  Math.sqrt(2*ymax0/G) ;
         x=0;  y=0 ;
         tTotal = 0;
         repaint() ;
         pause(250) ;
        for(t=0; t<=tb0; t+=dt)   {            // initial going down.
           y =  gb2*t*t  ;
           x = x+vx ;
           repaint() ;
           tTotal++ ;
           pause(tPause) ;
         }
         
         ymax = hn = ymax0 ;                  // initialize for loop.
     for (bounce=1; bounce<=1000; bounce++) {

              tn = con*Math.sqrt(Math.pow(2,1-bounce)) ;   // time for one-way bounce.
              hn=hn/2 ;                 //  decrease bounce height by two each bounce.
              ymax=ymax0 - hn ;         // distance from TOP down.
              vmax = Math.sqrt(g2*hn) ;     // maximum speed at bottom of fall.
                  for (t=0; t<=tn; t+=dt) {                    // going up.
                       y = ymax0 - vmax*t + gb2*t*t ;
                       x = x + vx ;
                       repaint() ;
                       tTotal++ ;
                       pause(tPause) ;
                     }

                  for(t=0; t<=tn; t+=dt) {                     // going down.
                       y =  ymax + gb2*t*t  ;
                       x = x + vx ;
                       tTotal++ ;
                       repaint() ;
                       pause(tPause) ;
                     }

         }       // end bounces.

 }              // end run

 public void update(Graphics g) {         
    paint(g);
     
    }
 

 public void paint(Graphics g) {           

    if(!Multi || (tTotal==0)) {
     offGr.setColor(Color.white) ;
     offGr.fillRect(0,0,wApp,hApp) ; 
     }
  offGr.setColor(Color.red) ;
  offGr.fillOval(x-ballRad, (int)(scale*y)-ballRad, ballDiam, ballDiam) ;
   g.drawImage(offIm,0,0,this) ;
 } 


  public boolean action(Event evt, Object arg) {
    if(evt.target instanceof Button) 
       controls((String)arg) ;
    else 
      if (evt.target instanceof TextField)
        valAdjust((TextField)evt.target) ;

     return true;
   }


  void controls(String butt) {
   if(butt.equals("Multi")) { 
     stop() ;
     Multi = !Multi ;
     start() ;
   } 
   else 
    if(butt.equals("Time"))
     lb1.setText("Time = " + String.valueOf(tTotal*dt)+ " sec") ;

  }

  void valAdjust(TextField data) {
       stop() ;
       Multi = false ;
       ymax0 = Double.valueOf(tf1.getText()).doubleValue() ;
       start() ;
   }

   public String getAppletInfo() {
   return "Copyright 1996 Michel Gallant";
  } 
 
}