Threads and Concurrent Programming

14.7 CASE STUDY: The Game of Pong

A Multithreaded Design

Let’s develop a multithreaded GUI to play the game of Pong.

Figure 14.29 shows how the game’s GUI should appear. There are three objects involved in this program: the frame, which serves as the GUI, the ball, which is represented as a blue circle in the program, and the paddle, which is represented by a red rectangle along the right edge of the frame. What cannot be seen in this figure is that the ball moves autonomously, bouncing off the walls and paddle. The paddle’s motion is controlled by the user by pressing the up- and down-arrow keys on the keyboard.

Annotation 2020-03-25 205352

We will develop class definitions for the ball, paddle, and the frame. Following the example of our dot-drawing program earlier in the Chapter, we will employ two independent threads, one for the GUI and one for the ball. Because the user will control the movements of the paddle, the frame will employ a listener object to listen for and respond to the user’s key presses.

Figure 14.30 provides an overview of the object-oriented design of the Pong program. The PongFrame class is the main class. It uses instances of the Ball and Paddle classes. PongFrame is a subclass of JFrame and implements the KeyListener interface.

Annotation 2020-03-25 205940

Figure 14.30: Design of the Pong program.

This is another of the several event handlers provided in the java.awt library. This one handles KeyEvents and the KeyListener interface consists of three abstract methods: keyPressed(), keyTyped(), and keyReleased(), all of which are associated with the act of pressing a key on the keyboard. All three of these methods are implemented in the PongFrame class. A key-typed event occurs when a key is pressed down. A key-release event occurs when a key that has been pressed down is released. A key-press event is a combination of both of these events.

The Ball class is a Thread subclass. Its data and methods are designed mainly to keep track of its motion within the program’s drawing panel. The design strategy employed here leaves the drawing of the ball up to the frame. The Ball thread itself just handles the movement within the program’s drawing panel. Note that the Ball() constructor takes a reference to the PongFrame. As we will see, the Ball uses this reference to set the dimensions of the frame’s drawing panel. Also, as the Ball moves, it will repeatedly call the frame’s repaint() method to draw the ball.

The Paddle class is responsible for moving the paddle up and down along the drawing panel’s right edge. Its public methods, moveUP() and moveDown(), will be called by the frame in response to the user pressing the up and down arrows on the keyboard. Because the frame needs to know where to draw the paddle, the paddle class contains several public methods, getX(), getY(), and resetLocation(), whose tasks are to report the paddle’s location or to adjust its location in case the frame is resized.

The PongFrame controls the overall activity of the program. Note in particular its ballHitsPaddle() method. This method has the task of determining when the ball and paddle come in contact as the ball continuously moves around in the frame’s drawing panel. As in the ThreadedDotty example earlier in the chapter, it is necessary for the Ball and the the frame to be implemented as separated threads so that the frame can be responsive to the user’s key presses.