Because the code has connected the menu items to an action listener, the application will use a method named actionPerformed that's called when the user makes a menu selection. This method is passed an ActionEvent object, whose getSource method returns the menu item the user selected. When the user selects the Start item, menuitem0, the application should begin a new game by telling the new thread to get things started. The standard technique for communicating with threads is with Boolean flags, and that's how you start a new game. In this case, the worker thread waits until a flag named stop is set to true before running the game. The user may have decided to start a new game in the middle of a current game, so the first order of business is to stop the current game if it's going and then redraw the empty hockey rink without any puckshere's what that looks like when the user selects the Start menu item: public void actionPerformed(ActionEvent e) { if(e.getSource() == menuitem0){ if(!stop){ stop = true; repaint(); } . . . } After stopping the current game (if there is one), the code calls a method named init (coming up next) to set up the new game. It also sets the stop flag to false to let the thread start running the game and then clears the scores in the two labels: public void actionPerformed(ActionEvent e) { if(e.getSource() == menuitem0){ if(!stop){ stop = true; repaint(); } init(); label1.setVisible(true); label2.setVisible(true); stop = false; label1.setText("0"); label2.setText("0"); yourScore = 0; theirScore = 0; } . . . } The init method creates a new vector of Puck objects, called pucks, stores the locations of the boundaries of the rink in a Rectangle object named edges, and creates all 12 pucks, numbered 0 to 11just as the fish in Aquarium were stored in a vector named fishes, so the pucks in Slapshot! are stored in a vector named pucks: CAUTION If you're using Java 1.4 instead of Java 1.5, omit the "<Puck>" part in the declaration of pucks.
This method also creates two special pucksthe computer's blocker, which it uses to fend off pucks, and the user's blocker, which the user can move with the mouse. These blockers are also Puck objects, which makes the logic where the various pucks bounce off other pucksand the blockersmuch easier to write. However, you'll need to give the blockers a different behavior than the pucks, because the computer moves one blocker and the user moves the other. For that reason, each Puck object has a type that you can setstandard pucks are type 0, the computer's blocker is type 1, and the user's is type 2. The difference is that blockers are not moveable by the puck-moving code, whereas pucks are, so the Puck method immovable returns false for pucks but true for blockers. This way, blockers are not inadvertently moved along with all the pucks. The type is passed to the Puck constructor as the second argument, like this, in init: public void init() { . . . for (int loopIndex = 0; loopIndex < 12; loopIndex++){ pucks.add(new Puck(gifImages[0], 0, maxVelocity, edges, this)); try { Thread.sleep(20); } catch (Exception exp) { System.out.println(exp.getMessage()); } } pucks.add(new Puck(gifImages[1], 1, maxVelocity, edges, this)); pucks.add(new Puck(gifImages[1], 2, maxVelocity, edges, this)); } This initializes all the sprites the application needs12 pucks, the user's blocker, and the computer's blocker. After this initialization, the stop flag is set to false so the new thread can start animating these sprites. In the run method, everything is enclosed in an if statement, waiting until stop is set to false (and like Aquarium, everything is enclosed inside a while loop that ends the whole application when the user closes the window or, in this case, selects the Exit item in the File menu): public void run() { Puck puck; while (runOK) { if(!stop){ . . . } } } |