CHAPTER 12 ■ VIDEO GAMES
The actionPerformed method also contains the game loop. That's not obvious because there's no
actual loop present. Instead, the Timer object calls the actionPerformed method each time the timer
ticks. As a result, we get a continuous loop so long as the timer runs. When you examine the
actionPerformed method, you can see that it does all three tasks that go in a game loop; it handles user
input (through the getActionCommand method), handles the game logic (by checking to see if the user has
clicked enough targets to end the game), and redraws the game area (by calling the repaint method of
the TargetClickPanel object).
The TargetPanel class provides the game field and keeps five targets in play. As part of keeping five
targets in play, it also checks to see if a mouse click in its area hits a target. Those functions are part of
the game logic. In this case, it's acceptable for the game logic to be distributed over more than one class.
The guiding principle is that each class has a clear, well-defined task. Keeping the right number of
targets in play and checking for targets being hit is part of managing the field of play, and that's the job
of the TargetClickPanel class. There's a lesson here: where possible, separate logic from user interface.
However, favor the principle of each class having a clear purpose over separating logic from
presentation. Ideally, you can achieve both goals, but that's not always practical (as here).
Listing 12-2. The TargetClickPanel class
package com.bryantcs.examples.videogames;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
public class TargetClickPanel extends JPanel implements MouseListener{
private static final long serialVersionUID = 1L;
// Keep track of the targets
private Target targets[] = new Target[5];
// The constructor, which populates the array with nulls
public TargetClickPanel() {
addMouseListener(this);
for (int i = 0; i < targets.length; i++) {
targets[i] = null;
}
}
// Here's where we update the game field
public void paint (Graphics g) {
super.paintComponent(g);
for (int i = 0; i < targets.length; i++) {
// here's where we make the initial targets
// on the first time through the loop
if (targets[i] == null) {
targets[i] = new Target(this);
}
// Is the target done (either fully drawn or has been clicked?)