Moving with the keyboard

Moving the unit around by prompting for input at the console is tedious to say the least. In this lesson we'll learn how to move the unit around on the board simply by pressing the directional arrows on the keyboard. Requires a browser that supports applets
This is meant to be a replacement when we do things (javascript menus) that might get hidden behind the applet.

Capturing keyboard events

There actually isn't a whole lot new to capturing key events. It will be very similar to capturing window events. We simply create a new adapter class and subscribe it to the window's key events.
import java.io.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

class StakeoutKeyAdapter extends KeyAdapter { public void keyPressed (KeyEvent event) { int keyId = event.getKeyCode (); if (keyId == KeyEvent.VK_UP) { Stakeout.unitRow = Stakeout.unitRow - 1; } else if (keyId == KeyEvent.VK_DOWN) { Stakeout.unitRow = Stakeout.unitRow + 1; } else if (keyId == KeyEvent.VK_LEFT) { Stakeout.unitColumn = Stakeout.unitColumn - 1; } else if (keyId == KeyEvent.VK_RIGHT) { Stakeout.unitColumn = Stakeout.unitColumn + 1; } Stakeout.component.repaint (); } }
class StakeoutWindowAdapter extends WindowAdapter { public void windowClosing (WindowEvent e) { System.out.println ("Game over!"); System.exit (0); } } class StakeoutComponent extends Component { public void StakeoutComponent () { setSize (300, 300); setVisible (true); } public void paint (Graphics canvas) { canvas.setColor (Color.BLACK); canvas.fillRect (0, 0, 300, 300); canvas.setColor (Stakeout.unitColor); canvas.fillRect ((Stakeout.unitColumn - 1) * 30, (Stakeout.unitRow - 1) * 30, 30, 30); } } public class Stakeout { public static int unitRow = 0; public static int unitColumn = 0; public static Color unitColor = Color.BLACK;
public static StakeoutComponent component;
public static void main (String args[]) throws IOException { System.out.println ("Welcome to Stakeout!"); // Prompt for the unit color boolean invalidColor = true; while (invalidColor) { System.out.println ("What color do you want your unit to be? [red or green]"); String input = CmdInput.GetInput (); if (input.contentEquals ("red")) { System.out.println ("You have chosen to be the Red Rebels!"); unitColor = Color.RED; invalidColor = false; } else if (input.contentEquals ("green")) { System.out.println ("You have chosen to be the Green Goblins!"); unitColor = Color.GREEN; invalidColor = false; } else { System.out.println ("You entered an invalid color!"); } } // Prompt for the initial unit row boolean invalidRow = true; while (invalidRow) { System.out.println ("What row do you want to start on? [1-10]"); String input = CmdInput.GetInput (); int startRow = Integer.valueOf (input).intValue (); if (startRow >= 1 && startRow <= 10) { System.out.println ("Starting row is " + startRow); unitRow = startRow; invalidRow = false; } else { System.out.println ("You entered an invalid row!"); } } // Prompt for the initial unit column boolean invalidColumn = true; while (invalidColumn) { System.out.println ("What column do you want to start on? [1-10]"); String input = CmdInput.GetInput (); int startColumn = Integer.valueOf (input).intValue (); if (startColumn >= 1 && startColumn <= 10) { System.out.println ("Starting column is " + startColumn); unitColumn = startColumn; invalidColumn = false; } else { System.out.println ("You entered an invalid column!"); } } // Setup the window System.out.println ("Creating the Stakeout window..."); JFrame window = new JFrame (); StakeoutWindowAdapter windowAdapter = new StakeoutWindowAdapter (); window.addWindowListener (windowAdapter);
StakeoutKeyAdapter keyAdapter = new StakeoutKeyAdapter (); window.addKeyListener (keyAdapter);
window.setTitle ("Stakeout Window Title"); window.setSize (340, 370); component = new StakeoutComponent (); window.add (component); window.setVisible (true); } }
The new class that we create to handle the keyboard events is called StakeoutKeyAdapter and it inherits from the KeyAdapter. It has several events that we can listen to, but the only one we're interested in right now is the keyPressed event. Like the window adapter function, this function gets an event argument that has the type KeyEvent. From this KeyEvent we extract the informaiton about which key was pressed and the we respond accordingly by changing the position of the unit similar to the last lesson. The keyId that we get from the KeyEvent is an integer that corresponds to one of the constants in the KeyEvent class. The only tricky thing here is that we have to call the repaint event on our component. Formerly we didn't have access to the component from any other class because it had function scope. To make the component accessible from our StakeoutKeyAdapter, it too has to be made a public static class member. The only other thing we need to do is to create an instance of our StakeoutKeyAdapter class and subscribe it to the window's events.

Constant values

Notice that all the "fields" in the KeyEvent's class use capital letters. This isn't necessary but it is a convention that constant values (values that don't change) like these use all capital letters. To enforce that these values don't change they are declared with the "final" keyword. We will use this ourselves in one of the later lessons.

Staying on the board

Stakeout is suppossed to be played on a board and units shouldn't be able to move off of the board. Keeping the units on the board is simply a matter of adding an extra conditional to the keyPressed function's "if" statements to gaurd against moving off the map. By now you should be able to figure this out.
    public void keyPressed (KeyEvent event) {
        int keyId = event.getKeyCode ();
        if (keyId == KeyEvent.VK_UP 
        && Stakeout.unitRow > 1) {
            Stakeout.unitRow = Stakeout.unitRow - 1;
        }
        else if (keyId == KeyEvent.VK_DOWN 
        && Stakeout.unitRow < 10) {
            Stakeout.unitRow = Stakeout.unitRow + 1;
        }
        else if (keyId == KeyEvent.VK_LEFT 
        && Stakeout.unitColumn > 1) {
            Stakeout.unitColumn = Stakeout.unitColumn - 1;
        }
        else if (keyId == KeyEvent.VK_RIGHT 
        && Stakeout.unitColumn < 10) {
            Stakeout.unitColumn = Stakeout.unitColumn + 1;
        }
        Stakeout.component.repaint ();
    }
We only have to make one comparison for each direction because if the user is moving up, it's impossible for him to move off of the bottom of the board, so we only have to check if he's moved off the top of the board. We can make this assumption here, but for certain things you have to check multiple conditions. Be careful about the assumptions you make.

Follow-up exercise

  • Exit the game when the Esc key is pressed
  • Change the unit color when the 'c' key is pressed


Rate this lesson: *****