Practical Exercise 16–Timers

This prac demonstrates how a Timer object can be used to create a simple animation or game involving a ball moving around the screen.

C Standard

Copy the following code into a Java applet and run it. You should see a green ball bouncing around inside a rectangle – but something is wrong!

Examine the code carefully and make the following changes:

  • fix the program so that the ball bounces off all the walls correctly
  • double the size of the bouncing ball
  • change the colour of the ball to blue
  • start the ball in the bottom right corner of the square
  • change the speed of the ball

import java.awt.*;

import java.applet.*;

import java.util.Timer;

import java.util.TimerTask;

publicclass Prac16_Timers_C extends Applet

{

Timer timer1;

intrefreshRate = 25;// in milliseconds

int[] rectangle = {5,5,300,200};// left, top, right, bottom

int[] position = {10,10};// ball position x,y

int[] velocity = {1, 3};// ball velocity x,y

intballSize = 20;

publicvoid init()

{

setSize(310,210);

timer1 = new Timer();

// the first number is initial delay, second number is refresh rate

timer1.schedule(new AnimationTask(), 0, refreshRate);

}

privateclass AnimationTask extends TimerTask

{

publicvoid run()// the code that you want to run repeatedly

{

ballBounce();

repaint();

}

}

publicvoid paint(Graphics g)

{

g.setColor(Color.black);

g.drawRect(rectangle[0], rectangle[1], rectangle[2]-rectangle[0], rectangle[3]-rectangle[1]);

g.setColor(Color.green);

g.fillOval(position[0], position[1], ballSize, ballSize);

}

publicvoid ballBounce()

{

//move the ball according to its velocity

position[0] += velocity[0];

position[1] += velocity[1];

//if the ball hits any side of the rectangle, change its direction

if(position[0]<=rectangle[0] || position[0]>=rectangle[2])

{

velocity[0]= -velocity[0];

}

if(position[1]<=rectangle[1] || position[1]>=rectangle[3])

{

velocity[1]= -velocity[1];

}

}

}

B Standard

The following example should do the same as the first example but the mouseListener and mouseMotionListener methods have been added. Copy this code then follow the steps below to add a swatter controlled by the mouse that can swat the bouncing ball.

import java.awt.*;

import java.applet.*;

import java.util.Timer;

import java.util.TimerTask;

import java.awt.event.*;

publicclass Prac16_Timers_B extends Applet implements MouseListener, MouseMotionListener

{

Timer timer1;

intrefreshRate = 25;// in milliseconds

int[] rectangle = {5,5,300,200};// left, top, right, bottom

int[] position = {10,10};// ball position x,y

int[] velocity = {1, 3};// ball velocity x,y

intballSize = 20;

intpaddleSize = 15;

int[] mouse={0,0};

booleanhit=false;

publicvoid init()

{

setSize(310,210);

addMouseListener(this);

addMouseMotionListener(this);

timer1 = new Timer();

timer1.schedule(new AnimationTask(), 0, refreshRate);

}

privateclass AnimationTask extends TimerTask

{

publicvoid run()

{

ballBounce();

repaint();

}

}

publicvoid paint(Graphics g)

{

//Draw the rectangle/game frame

g.setColor(Color.black);

g.drawRect(rectangle[0], rectangle[1], rectangle[2]-rectangle[0], rectangle[3]-rectangle[1]);

//Draw the bouncing ball

g.setColor(Color.green);

g.fillOval(position[0], position[1], ballSize, ballSize);

//Draw the paddle

g.setColor(Color.red);

g.fillRect(mouse[0], mouse[1], paddleSize, paddleSize);

}

publicvoid ballBounce()

{

//move the ball according to its velocity

position[0] += velocity[0];

position[1] += velocity[1];

//If the ball hits any sides of the rectangle, change its direction

if(position[0]<=rectangle[0] || position[0]>=rectangle[2]-ballSize)

{

velocity[0]= -velocity[0];

}

if(position[1]<=rectangle[1] || position[1]>=rectangle[3]-ballSize)

{

velocity[1]= -velocity[1];

}

}

publicboolean checkHit()

{

Boolean result = false;

//Write method body here

returnresult;

}

publicvoid mouseDragged(MouseEvent e)

{

}

publicvoid mouseMoved(MouseEvent e)

{

}

publicvoid mouseClicked(MouseEvent e)

{

}

publicvoid mouseEntered(MouseEvent e)

{

}

publicvoid mouseExited(MouseEvent e)

{

}

publicvoid mousePressed(MouseEvent e)

{

}

publicvoid mouseReleased(MouseEvent e)

{

}

}

To make the swatter move, add the following code to the mouseMoved method:

mouse[0]=e.getX();

mouse[1]=e.getY();

repaint();

Add the following code to the mouseClicked method:

mouse[0]=e.getX();

mouse[1]=e.getY();

if (checkHit())

{

timer.cancel();

}

repaint();

Edit the checkHit method to set the variable result to truewhen the swatter has ‘hit’ the bouncing ball.

This should now allow you to swat the ball (i.e. freeze it). Run the applet and check.

B+ Standard

How close do you have to be to swat it? How could this be adjusted?

The mouse has to be still when you click on it. Why? How would you fix this?

A Standard

Copy and paste the following object code into a new class called Ball in the same project folder.

publicclass Ball

{

intx, y, x_velocity, y_velocity, size;

public Ball(intx, inty, intx_velocity, inty_velocity, intsize)

{

this.x=x;

this.y=y;

this.x_velocity = x_velocity;

this.x_velocity = x_velocity;

this.size=size;

}

publicint getX()

{

returnx;

}

publicvoid setX(intx)

{

this.x = x;

}

publicint getY()

{

returny;

}

publicvoid setY(inty)

{

this.y = y;

}

publicint getX_velocity()

{

returnx_velocity;

}

publicvoid setX_velocity(intx_velocity)

{

this.x_velocity = x_velocity;

}

publicint getY_velocity()

{

returny_velocity;

}

publicvoid setY_velocity(inty_velocity)

{

this.y_velocity = y_velocity;

}

publicint getSize()

{

returnsize;

}

publicvoid setSize(intsize)

{

this.size = size;

}

publicvoid move()

{

//move the ball according to its velocity

x += x_velocity;

y += y_velocity;

}

publicvoid x_reverse()

{

x_velocity = -x_velocity;

}

publicvoid y_reverse()

{

y_velocity = -y_velocity;

}

}

Copy your code from Prac16_Timers_B and copy it into a new class called Prac16_Timers_A.

Edit this code to usethe Ball object, rather than using the position and velocity variables.

Create a second timer and a second ball object – use these to enable two balls to bounce around the frame and be independently stopped with the one swatter

Extension Task 1

Create a version of pong.

You will need to incorporate your knowledge of the keyboard listener to get this working.

  1. Create an applet and draw the pong board:
  • a rectangle
  • two ‘gutters’
  • a centre line
  1. Make sure the left and right gutters are stored as variables.
  2. Incorporate your bouncing ball code, make sure it bounces off the gutters, not the rectangle.
  3. Draw two paddles – left and right.
  • Make sure their x- and y-values and their height are stored in variables.
  • You may choose to create a Paddle object OR code them into the main class – it is your choice.
  1. Incorporate the KeyListener.
  • Control the left paddles up movement with the ‘w’ key and down movement with the ‘s’ key.
  • Control the right paddle with the up and down arrow keys.
  1. Make sure that the paddles do not go past the top or bottom edges of the rectangle.
  2. Write code to allow the ball to bounce off the paddle, but stop if it hits the gutter.
  • Get collisions happening for the left paddle first, before moving on to the right paddle.
  • See diagram.
  • You need to test if the ball is between the top of the paddle and the bottom of the paddle, but you cannot test against the Y co-ordinate of the ball, you must test against the middle of the ball.
  • Eg.

if (ball_y + (ball_size/2) >= paddle_y)
// the ball hit below the top edge
// of the paddle

  1. Once the ball correctly stops when it hits either gutter, comment out the line that stops the ball, and add in a line that incorporates scoring and re-spawns the ball from the centre of the game.
  2. If the ball hits the right gutter, the left player should win a point and the ball should spawn in a way that will make it move upwards and to the left.
    If the ball hits the left gutter, the right player should win a point and the ball should spawn in a way that will make it move upwards and to the right.
  3. Write code to display these scores on the applet (see image).
  4. If you want to add in an additional level of difficulty, add code to increase the ball speed with each hit of the paddle.

Extension Task 2

To avoid a possible problem with flickering, you can use something called Double Buffering.

In the top of the class, paste the follow lines of code:

private Image dbImage; //double buffering

private Graphics dbg; //double buffering

After the init() method, paste in the following method:

//Double Buffering Method

publicvoid update (Graphics g)

{

if (dbImage == null)

{

dbImage = createImage (this.getSize().width, this.getSize().height);

dbg = dbImage.getGraphics();

}

dbg.setColor (getBackground ());

dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);

dbg.setColor (getForeground());

paint(dbg);

g.drawImage(dbImage, 0, 0, this);

}

Claremont College 2015, adapted from Rosny College 2009Page 1 of 8