Java: Example - Bouncing Ball

This program does a simple animation. Animation is done by creating a timer which calls an ActionListener at fixed intervals (eg, every 35 milliseconds). The listener tells the ball to move it's coordinates a little, then it repaints the panel. repaint() indirectly calls our paintComponent() method, which then draws the ball with the updated coordinates.

BBDemo.java - The main program and window creation

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
// File: animation/bb/BBDemo.java
// Description: Illustrates animation with a ball bouncing in a box
//              Possible extensions: faster/slower button,
// Author: Fred Swartz
// Date:   February 2005 ...

import javax.swing.*;

/////////////////////////////////////////////////////////////// BBDemo
public class BBDemo extends JApplet {
    
    //============================================== applet constructor
    public BBDemo() {
        add(new BBPanel());
    }
    
    //============================================================ main
    public static void main(String[] args) {
        JFrame win = new JFrame("Bouncing Ball Demo");
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        win.setContentPane(new BBPanel());
        
        win.pack();
        win.setVisible(true); 
    }
}//endclass BBDemo

BBPanel.java - The JPanel which organizes the GUI

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
// File:  animation/bb/BBPanel.java
// Description: Panel to layout buttons and graphics area.
// Author: Fred Swartz
// Date:   February 2005

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/////////////////////////////////////////////////////////////////// BBPanel
class BBPanel extends JPanel {
    BallInBox m_bb;   // The bouncing ball panel
    
    //========================================================== constructor
    /** Creates a panel with the controls and bouncing ball display. */
    BBPanel() {
        //... Create components
        m_bb = new BallInBox();        
        JButton startButton = new JButton("Start");        
        JButton stopButton  = new JButton("Stop");
        
        //... Add Listeners
        startButton.addActionListener(new StartAction());
        stopButton.addActionListener(new StopAction());
        
        //... Layout inner panel with two buttons horizontally
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        buttonPanel.add(startButton);
        buttonPanel.add(stopButton);
        
        //... Layout outer panel with button panel above bouncing ball
        this.setLayout(new BorderLayout());
        this.add(buttonPanel, BorderLayout.NORTH);
        this.add(m_bb       , BorderLayout.CENTER);
    }//end constructor
    
    
    ////////////////////////////////////// inner listener class StartAction
    class StartAction implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            m_bb.setAnimation(true);
        }
    }
    
    
    //////////////////////////////////////// inner listener class StopAction
    class StopAction implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            m_bb.setAnimation(false);
        }
    }
}//endclass BBPanel

BallInBox.java - The graphics panel that does the animation.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
// File:   animation/bb/BouncingBall.java
// Description: This Graphics panel simulates a ball bouncing in a box.
//         Animation is done by changing instance variables
//         in the timer's actionListener, then calling repaint().
//         * Flicker can be reduced by drawing into a BufferedImage, 
//           and/or using a clip region.
//         * The edge of the oval could be antialiased (using Graphics2).
// Author: Fred Swartz
// Date:   February 2005

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/////////////////////////////////////////////////////////////// BouncingBall
public class BallInBox extends JPanel {
    //============================================== fields
    //... Instance variables representing the ball.
    private Ball m_ball         = new Ball(0, 0, 2, 3);
    
    //... Instance variables for the animiation
    private int   m_interval  = 35;  // Milliseconds between updates.
    private Timer m_timer;           // Timer fires to anmimate one step.

    //========================================================== constructor
    /** Set panel size and creates timer. */
    public BallInBox() {
        setPreferredSize(new Dimension(200, 80));
        setBorder(BorderFactory.createLineBorder(Color.BLACK));
        m_timer = new Timer(m_interval, new TimerAction());
    }
    
    //========================================================= setAnimation
    /** Turn animation on or off.
     *@param turnOnOff Specifies state of animation.
     */
    public void setAnimation(boolean turnOnOff) {
        if (turnOnOff) {
            m_timer.start();  // start animation by starting the timer.
        } else {
            m_timer.stop();   // stop timer
        }
    }

    //======================================================= paintComponent
    public void paintComponent(Graphics g) {
        super.paintComponent(g);  // Paint background, border
        m_ball.draw(g);           // Draw the ball.
    }
    
    //////////////////////////////////// inner listener class ActionListener
    class TimerAction implements ActionListener {
        //================================================== actionPerformed
        /** ActionListener of the timer.  Each time this is called,
         *  the ball's position is updated, creating the appearance of
         *  movement.
         *@param e This ActionEvent parameter is unused.
         */
        public void actionPerformed(ActionEvent e) {
            m_ball.setBounds(getWidth(), getHeight());
            m_ball.move();  // Move the ball.
            repaint();      // Repaint indirectly calls paintComponent.
        }
    }
}//endclass

Ball.java - The logic/model of the ball.

This class holds the information about the ball, its diameter, position, and velocity. Other attributes are possible (eg, color). This ball knows nothing about animation, only about its current state, how to update its coordinates, and how to draw itself.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
// File: animation/bb/BallModel.java
// Description: The logic / model of a ball.
// Author: Fred Swartz
// Date:   February 2005

import java.awt.*;

///////////////////////////////////////////////////////////////// BallModel
public class Ball {
    //... Constants
    final static int DIAMETER = 21;
    
    //... Instance variables
    private int m_x;           // x and y coordinates upper left
    private int m_y;
    
    private int m_velocityX;   // Pixels to move each time move() is called.
    private int m_velocityY;
    
    private int m_rightBound;  // Maximum permissible x, y values.
    private int m_bottomBound;
    
    //======================================================== constructor
    public Ball(int x, int y, int velocityX, int velocityY) {
        m_x = x;
        m_y = y;
        m_velocityX = velocityX;
        m_velocityY = velocityY;
    }
    
    //======================================================== setBounds
    public void setBounds(int width, int height) {
        m_rightBound  = width  - DIAMETER;
        m_bottomBound = height - DIAMETER;
    }
    
    //============================================================== move
    public void move() {
        //... Move the ball at the give velocity.
        m_x += m_velocityX;
        m_y += m_velocityY;        
        
        //... Bounce the ball off the walls if necessary.
        if (m_x < 0) {                  // If at or beyond left side
            m_x         = 0;            // Place against edge and
            m_velocityX = -m_velocityX; // reverse direction.
            
        } else if (m_x > m_rightBound) { // If at or beyond right side
            m_x         = m_rightBound;    // Place against right edge.
            m_velocityX = -m_velocityX;  // Reverse direction.
        }
        
        if (m_y < 0) {                 // if we're at top
            m_y       = 0;
            m_velocityY = -m_velocityY;
            
        } else if (m_y > m_bottomBound) { // if we're at bottom
            m_y       =  m_bottomBound;
            m_velocityY = -m_velocityY;
        }
    }
    
    //============================================================== draw
    public void draw(Graphics g) {
        g.fillOval(m_x, m_y, DIAMETER, DIAMETER);
    }
    
    //============================================= getDiameter, getX, getY
    public int  getDiameter() { return DIAMETER;}
    public int  getX()        { return m_x;}
    public int  getY()        { return m_y;}
    
    //======================================================== setPosition
    public void setPosition(int x, int y) {
        m_x = x;
        m_y = y;
    }
}