// BouncingBallSimpleApplet.java (c) Kari Laitinen // http://www.naturalprogramming.com // 2007-01-29 File created. // 2008-02-08 Implemented as a JPanel-based applet. // 2008-02-10 Name is now BouncingBallSimpleApplet.java. // This program shows a ball that moves on the screen. // The ball bounces when it hits a 'wall' or a paddle. // You can move the paddle with the Arrow Up and Arrow Down keys. /* Nice exercises with this program: 1. Because the ball is still somewaht blurred, although this is now a JPanel-based applet, consider using active rendering. 2. The movement of the ball is not always nice when it is near the paddle. If you run this program for a longer period of time, you'll see that sometimes the ball traverses through the paddle. Remove this problem from the program. 3. Add another BouncingBall object to the applet. 4. Count, inside the BouncingBall class, how many times the ball in question hits the 'Eastern' wall. */ import java.awt.* ; import java.awt.event.* ; import javax.swing.* ; import java.awt.geom.* ; class BouncingBall extends Ball { int velocity_in_pixels = 4 ; int x_increment = - velocity_in_pixels ; int y_increment = - velocity_in_pixels ; Rectangle2D.Double bouncing_area ; Paddle paddle ; public BouncingBall( int given_position_x, int given_position_y, Color given_color, Rectangle2D.Double given_bouncing_area, Paddle given_paddle ) { super( given_position_x, given_position_y, given_color ) ; bouncing_area = given_bouncing_area ; paddle = given_paddle ; } public void move() { ball_position_x += x_increment ; ball_position_y += y_increment ; /* The following is the first attempt to handle interaction with the paddle. if ( this.intersects_rectangle( paddle.get_paddle_area() ) ) { //////x_increment = x_increment * (-1) ; if ( x_increment > 0 ) // left-to-right movement going on { x_increment = - velocity_in_pixels ; // let's just turn back } else { x_increment = velocity_in_pixels ; } }***/ // The following if-else if-else if ... construct is the second // attempt to handle bouncing from the paddle. This does not // work either. Rectangle2D.Double paddle_area = paddle.get_paddle_area() ; if ( ( new Rectangle( (int) paddle_area.x, (int) paddle_area.y - ball_diameter / 2, (int) paddle_area.width, ball_diameter / 2 ) ).contains( ball_position_x + ball_diameter / 2, ball_position_y + ball_diameter / 2 ) ) { // the ball hits the northers side of the rectangular obstacle y_increment = - velocity_in_pixels ; } else if ( ( new Rectangle( (int) paddle_area.x, (int) (paddle_area.y + paddle_area.height ), (int) paddle_area.width, ball_diameter / 2 ) ).contains( ball_position_x + ball_diameter / 2, ball_position_y + ball_diameter / 2 ) ) { // the ball hits the southern wall of the rectangular obstacle y_increment = velocity_in_pixels ; } else if ( ( new Rectangle( (int) paddle_area.x - ball_diameter / 2, (int) paddle_area.y, ball_diameter / 2, (int) paddle_area.height ) ).contains( ball_position_x + ball_diameter / 2, ball_position_y + ball_diameter / 2 ) ) { // the ball hits the western wall of the rectangular obstacle x_increment = - velocity_in_pixels ; } else if ( ( new Rectangle( (int) (paddle_area.x + paddle_area.width), (int) paddle_area.y, ball_diameter / 2, (int) paddle_area.height ) ).contains( ball_position_x + ball_diameter / 2, ball_position_y + ball_diameter / 2 ) ) { // the ball hits the eastern wall of the rectangular obstacle x_increment = velocity_in_pixels ; } if ( ball_position_y <= bouncing_area.y ) { y_increment = velocity_in_pixels ; } if ( ball_position_x <= bouncing_area.x ) { x_increment = velocity_in_pixels ; } if ( ( ball_position_y + ball_diameter ) >= ( bouncing_area.y + bouncing_area.height ) ) { y_increment = - velocity_in_pixels ; } if ( ( ball_position_x + ball_diameter ) >= ( bouncing_area.x + bouncing_area.width ) ) { x_increment = - velocity_in_pixels ; } } } class Paddle { Rectangle2D.Double paddle_shape ; public Paddle( int given_position_x, int given_position_y ) { paddle_shape = new Rectangle2D.Double( given_position_x, given_position_y, 5, 70 ) ; } public Rectangle2D.Double get_paddle_area() { return paddle_shape ; } public void move_up() { paddle_shape.setRect( paddle_shape.x, paddle_shape.y - 10, paddle_shape.width, paddle_shape.height ) ; } public void move_down() { paddle_shape.setRect( paddle_shape.x, paddle_shape.y + 10, paddle_shape.width, paddle_shape.height ) ; } public void draw( Graphics graphics ) { Graphics2D graphics2D = (Graphics2D) graphics ; graphics2D.fill( paddle_shape ) ; } } class BouncingBallPanel extends JPanel implements KeyListener, Runnable { Thread thread_that_moves_the_ball ; boolean thread_must_be_executed ; JButton left_button, up_button, down_button, right_button ; int applet_width, applet_height ; BouncingBall ball_on_screen ; Paddle paddle_on_screen ; public BouncingBallPanel( int given_applet_width, int given_applet_height ) { applet_width = given_applet_width ; applet_height = given_applet_height ; Rectangle2D.Double bouncing_area = new Rectangle2D.Double( 0, 0, applet_width, applet_height ) ; paddle_on_screen = new Paddle( applet_width / 3 * 2, applet_height / 2 ) ; ball_on_screen = new BouncingBall( applet_width / 2 - 40, applet_height / 2 - 40, Color.red, bouncing_area, paddle_on_screen ) ; addKeyListener( this ) ; } public void start_animation_thread() { if ( thread_that_moves_the_ball == null ) { thread_must_be_executed = true ; thread_that_moves_the_ball = new Thread( this ) ; thread_that_moves_the_ball.start() ; } } public void stop_animation_thread() { if ( thread_that_moves_the_ball != null ) { thread_must_be_executed = false ; thread_that_moves_the_ball.interrupt() ; thread_that_moves_the_ball = null ; } } public void run() { while ( thread_must_be_executed == true ) { ball_on_screen.move() ; repaint() ; try { Thread.sleep( 40 ) ; } catch ( InterruptedException caught_exception ) { // No actions to handle the exception. } } } public void keyPressed( KeyEvent event ) { int key_code = event.getKeyCode() ; if ( key_code == KeyEvent.VK_UP ) { paddle_on_screen.move_up() ; } else if ( key_code == KeyEvent.VK_DOWN ) { paddle_on_screen.move_down() ; } // repaint() ; } public void keyReleased( KeyEvent event ) { } public void keyTyped( KeyEvent event ) { } public void paintComponent( Graphics graphics ) { super.paintComponent( graphics ) ; ball_on_screen.draw( graphics ) ; graphics.setColor( Color.black ) ; graphics.drawString( "(" + ball_on_screen.get_ball_position_x() + ", " + ball_on_screen.get_ball_position_y() + ")", 20, 20 ) ; paddle_on_screen.draw( graphics ) ; // A window has 'focus' when keyboard input is directed to it. // The following statement ensures that the applet window will // receive keyboard input. if ( ! hasFocus() ) { requestFocus() ; } } } public class BouncingBallSimpleApplet extends JApplet { BouncingBallPanel panel_for_the_bouncing_ball ; public void init() { panel_for_the_bouncing_ball = new BouncingBallPanel( getSize().width, getSize().height ); getContentPane().add( panel_for_the_bouncing_ball ) ; } public void start() { panel_for_the_bouncing_ball.start_animation_thread() ; } public void stop() { panel_for_the_bouncing_ball.stop_animation_thread() ; } }