Csci 210 Lab3: Pong

(Laura Toma adapted from Eric Chown)


In this lab we are going to go back to the start of the video game era and implement a game called Pong. In Pong there are paddles and balls and your job is not to let the ball get past your paddle.

For this lab we will concentrate on a simple single paddle, single ball game. If you write nice general code you should easily be able to scale it up to more advanced versions of the game (like Breakout--- which will be one of the next labs).

To get an idea of how it will look like check this out: Pong.jar | PongL.jar. They are obviously not perfect, and they should not be considered a standard; but they should give you an idea of what to shoot for in this lab.

Your program will consist of three classes:

  1. the Pong class
  2. the Paddle class
  3. the Ball class

We will discuss them in turn.

The Pong Class

The first class is the Pong class itself. It is basically the game controller. The Pong class will handle all of the graphics for the program. Therefore it should extend the JFrame class just as your class for the last lab did. It will also need to listen for mouse movements as the player controls the paddle so it will need to implement the MouseMotionListener interface and all of the corresponding methods. Finally, it will need to tell the ball when to move through the use of a Timer. The Timer will set of timer event so your class will need to be able to listen for it. It does that by implementing the ActionListener interface.

The code for the Pong class is relatively simple. The constructor just makes a new window (like you did in the last lab), adds the appropriate listeners and makes a ball, a paddle and starts the Timer.

Pong: Drawing

As we discussed in class, many java programs do all of their drawing in a
 public void paint(Graphics g) 
method. This is already defined for the JFrame class, but for this program you will want to over-ride it and provide your own version of the method. In Java the paint method is called every time Java thinks that the screen needs refreshing (for example when you minimize the window).

One counter-intuitive thing about using paint in Java is how to call it. You don't force the program to paint by directly calling paint (in fact it is a bad idea). You do it by calling the method repaint(). Repaint is actually a Java directive which tells the Java Virtual machine to please call paint as soon as it is convenient. You do not write your own repaint method!

For this program your paint method will be very short: it will clear everything, draw a rectangle to outline the game, then draw the paddle and finally the ball. Since the paint method in class Pong is doing the drawing, it needs to get its information from the other objects (e.g. the Ball and the Paddle). It should get the information for the paddle and the ball from the appropriate instances. E.g.

 g.fillOval(ball.getX(), ball.getY(), ball.getSize(), ball.getSize());
would draw the ball assuming you have written the ball class correctly. You'll have similar code for the paddle.

Even better, the Ball class would provide a method

void paintBall (Graphics g)
and the Pong class would call ball.paintBall(this.getGraphics()) whenever it would need to draw the ball. Note that Pong would need to pass it the Graphics object (canvas) on which to draw. Similar for the paddle.

Note: to clear everything before painting, your first line in paint should be

This calls paint on the ancesstors of your Pong class, and has the effect that it clears everything out.

Pong: Moving the Ball

The Pong class needs to tell the ball when to move through a timer. To get a Timer to work you first make a global Timer variable like so:
 private Timer timer; 
You actually need to be slightly careful about the Timer declaration as there are three different Timer classes in Java. To be on the safe side you might declare it this way:
private javax.swing.Timer timer;

Setting up a timer involves creating a Timer object, registering one or more action listeners on it, and starting the timer using the start method. For example, the following code creates and starts a timer that fires an action event once per MOVE milliseconds (as specified by the first argument to the Timer constructor). The second argument to the Timer constructor specifies a listener to receive the timer's action events.

//timer set to go off every MOVE milliseconds;
//the timer events are sent to actionListenerObject---this object must be
//an instance of a class that implements ActionListenerInterface
timer = new Timer(MOVE, actionListenerObject);

timer.setInitialDelay(1000);  //  Waits a 1000 milliseconds before starting
The timer in the example will go off every 25 milliseconds and create an event that your program listens for. The class that listens to the timer (the actionListenerObject above) will need an
public void actionPerformed(ActionEvent newEvent)
method. Remember that your Pong is implementing the ActionListener interface, so this is the method you need to fulfill that contract. The action that you are listening for in this case is the Timer going off. The action that you want to occur when the Timer goes off is that the ball should move. So your method will tell the ball object to move.

You can, if you need to, add more than one listeners to a timer. If you wanted the ball to listen to the timer as well, you could say something like

In this case the ball would need to implement the ActionListener interface.

Note that in this scenario, Pong listens to the timer and on every timer events calls ball.move(). Another scenario would be for the ball to listen to the timer and move on its own; in this case the ball would have to implement the ActionListener interface. If you chose to implement this other scenario, that is fine, but you need to argue why you prefer it.

The following link may be useful (or not): How to use Swing timers.

Pong: Moving the Paddle

The paddle moves as the mouse moves. So your Pong:mouseMoved(MouseEvent e) will tell the paddle to move (following the mouse). And then will call repaint().

Note that Pong tells the paddle to move; however all the logic for figuring out how to move (or whether or not to move) should be in the Paddle class.

The Paddle Class

The Paddle class is going to be functionally similar to a Rectangle with some extra restrictions. It would be nice to build a general paddle that is useful in many games, not just Pong. In Pong, the Paddle will only move in the X direction and it will stop at the boundaries of the Pong window. With both of those things in mind you will probably want to pass your Paddle constructor the boundaries that it can move in both the X and Y directions (remember this should work as a general Paddle, not just for your particular game, for another it might only move vertically). As an alternative you could simply specify which dimension the paddle can move in, and then the boundaries in that direction. You should also pass the Paddle its dimensions (width and height).

Your Paddle should have "getters" for its X and Y values as well as its width and height. It should also have a contains method (more on that later - your Ball class will need it). Finally it should have a move(x, y) method to move it as the mouse moves. Remember, however, that it should not move outside the legal game boundaries.

You might find it useful in implementing the Paddle class to use the Java Rectangle class, or the Rectangle2D.Double class. These classes would be useful for implementing contains, as well as for tracking where the paddle is (using the setLocation(x, y)) method.

The contains method (or alternatively an intersect method) is probably the key part of the program and almost certainly the most difficult. The idea is that other objects should never pierce your paddle, instead they should bounce off it. Among other things this means you need to be able to tell if two objects intersect each other. If you really want to do a nice job with it, it is also useful to figure out where they would hit. There are many strategies for doing this. One thing to think about is that hitting the side of the paddle might be quite different from hitting the top of the paddle. What this suggests is that instead of thinking of your paddle as a single rectangle, you might think of several smaller rectangles (perhaps including Rectangles within the class instead of simply extending the Rectangle class).

The Ball Class

The Ball class will be similar to the Paddle class. It too should be as general as possible. It will have getters for X, Y and Size. The major difference is that the Ball moves more or less on its own (in response to the timer).

In addition to tracking the ball's location you'll also need to keep track of its speed in both the X and Y directions. Each time the move() method is called the ball should move that many pixels in the appropriate direction. The tricky part is that the ball should recognize when it hits either a wall, the ceiling, or the paddle. If it hits a wall its X speed should be reversed. If it hits the ceiling its Y speed should be reversed and if it hits the paddle both should be reversed. Since it needs to figure all of these things out your ball constructor should take in the field dimensions as well as the instance of the Paddle class created in your Pong class. Then when it wants to check if it hit the Paddle it can do so by calling the Paddle's contains (or intersects) method. Alternatively (and perhaps even better) you could have the Ball call a boundary method to check if it is running into something.

Ideally the speed of the ball should be initially set somewhat randomly (e.g. give each dimension a value between 2 and 5). For starters I would just fix them at some constant (I used 3 in each dimension).

One thing to be careful about---when the Ball runs into a paddle (or a wall) it should not literally go into the paddle (its movement should end on the paddle boundary). It's a common error to have Balls get stuck inside paddles.

The ball speed changes that I outline above are merely guidelines. It is reasonable to make the behaviors more interesting. For example the actual part of the paddle you hit might affect the directional change. Or a moving paddle might add velocity, you might change the velocity the longer the program runs, etc. It isn't necessary to do any of this, but you are always encouraged to have fun with your programs.

Other Constants

Feel free to experiment with different dimensions, paddle sizes, colors, etc. Just try and keep them so they are playable. The following values are probably a reasonable place to start.
//position and dimensions of the court
private static final int COURT_LEFT = 100;
private static final int COURT_TOP = 50;
private static final int COURT_HEIGHT = 300;
private static final int COURT_WIDTH = 250;

// location and dimensions of the paddle
private static final int PADDLE_WIDTH = 50;
private static final int PADDLE_HEIGHT = 20;
private static final int PADDLE_TOP = COURT_TOP + COURT_HEIGHT - PADDLE_HEIGHT -1;

private static final int BALLSIZE = 30;
private static final int MOVE = 25;


There are a lot of possible extensions to this program. You could add levels such that the game gets harder as the player survives (e.g. the paddle gets narrower, the ball moves faster, etc.). You could provide the opportunity to have multiple balls. Or multiple paddles for a two player game (look into the KeyListener class for this). By the way, if you do a two player game you still should have a single player mode. I need to test it!

Warning: your game should be playable. It is bad practice to have it set up so that I have virtually no chance to play your game. I need to test your program. Please make that process as painless as possible, don't start your game at super fast speeds! There are few things more frustrating then hitting the new Pong command and then seeing the ball race down before I can move the mouse over to the window to stop it. It might be helpful to think about a "start" button and a "new game" button. Those help in playability.

Handing in today by the end of the lab

  1. A diagram sketching the instance variables and the interface of each class.
  2. A flowchart/diagram/writeup (chose one) that outlines the logic of your program: describe how your Pong controller will work and describe how you will handle collisions ball-walls, ball-paddle. Who listens to the timer? How is the movement handled?
  3. Write, in incremental order, the steps in which you will write the program.

Handing in by next week:

The full code of the program is due one week from today. As always, hand in hard copy in addition to emailing me the code. Either email me the java files as attachments, or place your classes in a folder called , and zip/tar it. Please don't email me any .class files, and no BlueJ-related files. On the hard-copy sign that you followed the honor code for the class.

Grading Scheme

Here is the grading scheme for this lab: Pong grading scheme.
Last modified: Thu Oct 9 21:54:23 EDT 2008