Mega Code Archive

 
Categories / Java / Game
 

Game-Swing

/* DEVELOPING GAME IN JAVA  Caracteristiques Editeur : NEW RIDERS  Auteur : BRACKEEN  Parution : 09 2003  Pages : 972  Isbn : 1-59273-005-1  Reliure : Paperback  Disponibilite : Disponible a la librairie  */ import java.awt.AWTException; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Composite; import java.awt.Container; import java.awt.Cursor; import java.awt.DisplayMode; import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Robot; import java.awt.Toolkit; import java.awt.Transparency; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; /**  * Extends the InputManagerTest demo and adds Swing buttons for pause, config  * and quit.  */ public class MenuTest extends InputManagerTest implements ActionListener {   public static void main(String[] args) {     new MenuTest().run();   }   protected GameAction configAction;   private JButton playButton;   private JButton configButton;   private JButton quitButton;   private JButton pauseButton;   private JPanel playButtonSpace;   public void init() {     super.init();     // make sure Swing components don't paint themselves     NullRepaintManager.install();     // create an addtional GameAction for "config"     configAction = new GameAction("config");     // create buttons     quitButton = createButton("quit", "Quit");     playButton = createButton("play", "Continue");     pauseButton = createButton("pause", "Pause");     configButton = createButton("config", "Change Settings");     // create the space where the play/pause buttons go.     playButtonSpace = new JPanel();     playButtonSpace.setOpaque(false);     playButtonSpace.add(pauseButton);     JFrame frame = super.screen.getFullScreenWindow();     Container contentPane = frame.getContentPane();     // make sure the content pane is transparent     if (contentPane instanceof JComponent) {       ((JComponent) contentPane).setOpaque(false);     }     // add components to the screen's content pane     contentPane.setLayout(new FlowLayout(FlowLayout.LEFT));     contentPane.add(playButtonSpace);     contentPane.add(configButton);     contentPane.add(quitButton);     // explicitly layout components (needed on some systems)     frame.validate();   }   /**    * Extends InputManagerTest's functionality to draw all Swing components.    */   public void draw(Graphics2D g) {     super.draw(g);     JFrame frame = super.screen.getFullScreenWindow();     // the layered pane contains things like popups (tooltips,     // popup menus) and the content pane.     frame.getLayeredPane().paintComponents(g);   }   /**    * Changes the pause/play button whenever the pause state changes.    */   public void setPaused(boolean p) {     super.setPaused(p);     playButtonSpace.removeAll();     if (isPaused()) {       playButtonSpace.add(playButton);     } else {       playButtonSpace.add(pauseButton);     }   }   /**    * Called by the AWT event dispatch thread when a button is pressed.    */   public void actionPerformed(ActionEvent e) {     Object src = e.getSource();     if (src == quitButton) {       // fire the "exit" gameAction       super.exit.tap();     } else if (src == configButton) {       // doesn't do anything (for now)       configAction.tap();     } else if (src == playButton || src == pauseButton) {       // fire the "pause" gameAction       super.pause.tap();     }   }   /**    * Creates a Swing JButton. The image used for the button is located at    * "../images/menu/" + name + ".png". The image is modified to create a    * "default" look (translucent) and a "pressed" look (moved down and to the    * right).    * <p>    * The button doesn't use Swing's look-and-feel and instead just uses the    * image.    */   public JButton createButton(String name, String toolTip) {     // load the image     String imagePath = "../images/menu/" + name + ".png";     ImageIcon iconRollover = new ImageIcon(imagePath);     int w = iconRollover.getIconWidth();     int h = iconRollover.getIconHeight();     // get the cursor for this button     Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);     // make translucent default image     Image image = screen.createCompatibleImage(w, h,         Transparency.TRANSLUCENT);     Graphics2D g = (Graphics2D) image.getGraphics();     Composite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,         .5f);     g.setComposite(alpha);     g.drawImage(iconRollover.getImage(), 0, 0, null);     g.dispose();     ImageIcon iconDefault = new ImageIcon(image);     // make a pressed iamge     image = screen.createCompatibleImage(w, h, Transparency.TRANSLUCENT);     g = (Graphics2D) image.getGraphics();     g.drawImage(iconRollover.getImage(), 2, 2, null);     g.dispose();     ImageIcon iconPressed = new ImageIcon(image);     // create the button     JButton button = new JButton();     button.addActionListener(this);     button.setIgnoreRepaint(true);     button.setFocusable(false);     button.setToolTipText(toolTip);     button.setBorder(null);     button.setContentAreaFilled(false);     button.setCursor(cursor);     button.setIcon(iconDefault);     button.setRolloverIcon(iconRollover);     button.setPressedIcon(iconPressed);     return button;   } } /**  * InputManagerTest tests the InputManager with a simple run-and-jump mechanism.  * The player moves and jumps using the arrow keys and the space bar.  * <p>  * Also, InputManagerTest demonstrates pausing a game by not updating the game  * elements if the game is paused.  */ class InputManagerTest extends GameCore {   public static void main(String[] args) {     new InputManagerTest().run();   }   protected GameAction jump;   protected GameAction exit;   protected GameAction moveLeft;   protected GameAction moveRight;   protected GameAction pause;   protected InputManager inputManager;   private Player player;   private Image bgImage;   private boolean paused;   public void init() {     super.init();     Window window = screen.getFullScreenWindow();     inputManager = new InputManager(window);     // use these lines for relative mouse mode     //inputManager.setRelativeMouseMode(true);     //inputManager.setCursor(InputManager.INVISIBLE_CURSOR);     createGameActions();     createSprite();     paused = false;   }   /**    * Tests whether the game is paused or not.    */   public boolean isPaused() {     return paused;   }   /**    * Sets the paused state.    */   public void setPaused(boolean p) {     if (paused != p) {       this.paused = p;       inputManager.resetAllGameActions();     }   }   public void update(long elapsedTime) {     // check input that can happen whether paused or not     checkSystemInput();     if (!isPaused()) {       // check game input       checkGameInput();       // update sprite       player.update(elapsedTime);     }   }   /**    * Checks input from GameActions that can be pressed regardless of whether    * the game is paused or not.    */   public void checkSystemInput() {     if (pause.isPressed()) {       setPaused(!isPaused());     }     if (exit.isPressed()) {       stop();     }   }   /**    * Checks input from GameActions that can be pressed only when the game is    * not paused.    */   public void checkGameInput() {     float velocityX = 0;     if (moveLeft.isPressed()) {       velocityX -= Player.SPEED;     }     if (moveRight.isPressed()) {       velocityX += Player.SPEED;     }     player.setVelocityX(velocityX);     if (jump.isPressed() && player.getState() != Player.STATE_JUMPING) {       player.jump();     }   }   public void draw(Graphics2D g) {     // draw background     g.drawImage(bgImage, 0, 0, null);     // draw sprite     g.drawImage(player.getImage(), Math.round(player.getX()), Math         .round(player.getY()), null);   }   /**    * Creates GameActions and maps them to keys.    */   public void createGameActions() {     jump = new GameAction("jump", GameAction.DETECT_INITAL_PRESS_ONLY);     exit = new GameAction("exit", GameAction.DETECT_INITAL_PRESS_ONLY);     moveLeft = new GameAction("moveLeft");     moveRight = new GameAction("moveRight");     pause = new GameAction("pause", GameAction.DETECT_INITAL_PRESS_ONLY);     inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);     inputManager.mapToKey(pause, KeyEvent.VK_P);     // jump with spacebar or mouse button     inputManager.mapToKey(jump, KeyEvent.VK_SPACE);     inputManager.mapToMouse(jump, InputManager.MOUSE_BUTTON_1);     // move with the arrow keys...     inputManager.mapToKey(moveLeft, KeyEvent.VK_LEFT);     inputManager.mapToKey(moveRight, KeyEvent.VK_RIGHT);     // ... or with A and D.     inputManager.mapToKey(moveLeft, KeyEvent.VK_A);     inputManager.mapToKey(moveRight, KeyEvent.VK_D);     // use these lines to map player movement to the mouse     //inputManager.mapToMouse(moveLeft,     //  InputManager.MOUSE_MOVE_LEFT);     //inputManager.mapToMouse(moveRight,     //  InputManager.MOUSE_MOVE_RIGHT);   }   /**    * Load images and creates the Player sprite.    */   private void createSprite() {     // load images     bgImage = loadImage("../images/background.jpg");     Image player1 = loadImage("../images/player1.png");     Image player2 = loadImage("../images/player2.png");     Image player3 = loadImage("../images/player3.png");     // create animation     Animation anim = new Animation();     anim.addFrame(player1, 250);     anim.addFrame(player2, 150);     anim.addFrame(player1, 150);     anim.addFrame(player2, 150);     anim.addFrame(player3, 200);     anim.addFrame(player2, 150);     player = new Player(anim);     player.setFloorY(screen.getHeight() - player.getHeight());   } } /**  * The Player extends the Sprite class to add states (STATE_NORMAL or  * STATE_JUMPING) and gravity.  */ class Player extends Sprite {   public static final int STATE_NORMAL = 0;   public static final int STATE_JUMPING = 1;   public static final float SPEED = .3f;   public static final float GRAVITY = .002f;   private int floorY;   private int state;   public Player(Animation anim) {     super(anim);     state = STATE_NORMAL;   }   /**    * Gets the state of the Player (either STATE_NORMAL or STATE_JUMPING);    */   public int getState() {     return state;   }   /**    * Sets the state of the Player (either STATE_NORMAL or STATE_JUMPING);    */   public void setState(int state) {     this.state = state;   }   /**    * Sets the location of "floor", where the Player starts and lands after    * jumping.    */   public void setFloorY(int floorY) {     this.floorY = floorY;     setY(floorY);   }   /**    * Causes the Player to jump    */   public void jump() {     setVelocityY(-1);     state = STATE_JUMPING;   }   /**    * Updates the player's positon and animation. Also, sets the Player's state    * to NORMAL if a jumping Player landed on the floor.    */   public void update(long elapsedTime) {     // set vertical velocity (gravity effect)     if (getState() == STATE_JUMPING) {       setVelocityY(getVelocityY() + GRAVITY * elapsedTime);     }     // move player     super.update(elapsedTime);     // check if player landed on floor     if (getState() == STATE_JUMPING && getY() >= floorY) {       setVelocityY(0);       setY(floorY);       setState(STATE_NORMAL);     }   } } /**  * The GameAction class is an abstract to a user-initiated action, like jumping  * or moving. GameActions can be mapped to keys or the mouse with the  * InputManager.  */ class GameAction {   /**    * Normal behavior. The isPressed() method returns true as long as the key    * is held down.    */   public static final int NORMAL = 0;   /**    * Initial press behavior. The isPressed() method returns true only after    * the key is first pressed, and not again until the key is released and    * pressed again.    */   public static final int DETECT_INITAL_PRESS_ONLY = 1;   private static final int STATE_RELEASED = 0;   private static final int STATE_PRESSED = 1;   private static final int STATE_WAITING_FOR_RELEASE = 2;   private String name;   private int behavior;   private int amount;   private int state;   /**    * Create a new GameAction with the NORMAL behavior.    */   public GameAction(String name) {     this(name, NORMAL);   }   /**    * Create a new GameAction with the specified behavior.    */   public GameAction(String name, int behavior) {     this.name = name;     this.behavior = behavior;     reset();   }   /**    * Gets the name of this GameAction.    */   public String getName() {     return name;   }   /**    * Resets this GameAction so that it appears like it hasn't been pressed.    */   public void reset() {     state = STATE_RELEASED;     amount = 0;   }   /**    * Taps this GameAction. Same as calling press() followed by release().    */   public synchronized void tap() {     press();     release();   }   /**    * Signals that the key was pressed.    */   public synchronized void press() {     press(1);   }   /**    * Signals that the key was pressed a specified number of times, or that the    * mouse move a spcified distance.    */   public synchronized void press(int amount) {     if (state != STATE_WAITING_FOR_RELEASE) {       this.amount += amount;       state = STATE_PRESSED;     }   }   /**    * Signals that the key was released    */   public synchronized void release() {     state = STATE_RELEASED;   }   /**    * Returns whether the key was pressed or not since last checked.    */   public synchronized boolean isPressed() {     return (getAmount() != 0);   }   /**    * For keys, this is the number of times the key was pressed since it was    * last checked. For mouse movement, this is the distance moved.    */   public synchronized int getAmount() {     int retVal = amount;     if (retVal != 0) {       if (state == STATE_RELEASED) {         amount = 0;       } else if (behavior == DETECT_INITAL_PRESS_ONLY) {         state = STATE_WAITING_FOR_RELEASE;         amount = 0;       }     }     return retVal;   } } /**  * Simple abstract class used for testing. Subclasses should implement the  * draw() method.  */ abstract class GameCore {   protected static final int FONT_SIZE = 24;   private static final DisplayMode POSSIBLE_MODES[] = {       new DisplayMode(800, 600, 32, 0), new DisplayMode(800, 600, 24, 0),       new DisplayMode(800, 600, 16, 0), new DisplayMode(640, 480, 32, 0),       new DisplayMode(640, 480, 24, 0), new DisplayMode(640, 480, 16, 0) };   private boolean isRunning;   protected ScreenManager screen;   /**    * Signals the game loop that it's time to quit    */   public void stop() {     isRunning = false;   }   /**    * Calls init() and gameLoop()    */   public void run() {     try {       init();       gameLoop();     } finally {       screen.restoreScreen();     }   }   /**    * Sets full screen mode and initiates and objects.    */   public void init() {     screen = new ScreenManager();     DisplayMode displayMode = screen         .findFirstCompatibleMode(POSSIBLE_MODES);     screen.setFullScreen(displayMode);     Window window = screen.getFullScreenWindow();     window.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE));     window.setBackground(Color.blue);     window.setForeground(Color.white);     isRunning = true;   }   public Image loadImage(String fileName) {     return new ImageIcon(fileName).getImage();   }   /**    * Runs through the game loop until stop() is called.    */   public void gameLoop() {     long startTime = System.currentTimeMillis();     long currTime = startTime;     while (isRunning) {       long elapsedTime = System.currentTimeMillis() - currTime;       currTime += elapsedTime;       // update       update(elapsedTime);       // draw the screen       Graphics2D g = screen.getGraphics();       draw(g);       g.dispose();       screen.update();       // take a nap       try {         Thread.sleep(20);       } catch (InterruptedException ex) {       }     }   }   /**    * Updates the state of the game/animation based on the amount of elapsed    * time that has passed.    */   public void update(long elapsedTime) {     // do nothing   }   /**    * Draws to the screen. Subclasses must override this method.    */   public abstract void draw(Graphics2D g); } /**  * The ScreenManager class manages initializing and displaying full screen  * graphics modes.  */ class ScreenManager {   private GraphicsDevice device;   /**    * Creates a new ScreenManager object.    */   public ScreenManager() {     GraphicsEnvironment environment = GraphicsEnvironment         .getLocalGraphicsEnvironment();     device = environment.getDefaultScreenDevice();   }   /**    * Returns a list of compatible display modes for the default device on the    * system.    */   public DisplayMode[] getCompatibleDisplayModes() {     return device.getDisplayModes();   }   /**    * Returns the first compatible mode in a list of modes. Returns null if no    * modes are compatible.    */   public DisplayMode findFirstCompatibleMode(DisplayMode modes[]) {     DisplayMode goodModes[] = device.getDisplayModes();     for (int i = 0; i < modes.length; i++) {       for (int j = 0; j < goodModes.length; j++) {         if (displayModesMatch(modes[i], goodModes[j])) {           return modes[i];         }       }     }     return null;   }   /**    * Returns the current display mode.    */   public DisplayMode getCurrentDisplayMode() {     return device.getDisplayMode();   }   /**    * Determines if two display modes "match". Two display modes match if they    * have the same resolution, bit depth, and refresh rate. The bit depth is    * ignored if one of the modes has a bit depth of    * DisplayMode.BIT_DEPTH_MULTI. Likewise, the refresh rate is ignored if one    * of the modes has a refresh rate of DisplayMode.REFRESH_RATE_UNKNOWN.    */   public boolean displayModesMatch(DisplayMode mode1, DisplayMode mode2)   {     if (mode1.getWidth() != mode2.getWidth()         || mode1.getHeight() != mode2.getHeight()) {       return false;     }     if (mode1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI         && mode2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI         && mode1.getBitDepth() != mode2.getBitDepth()) {       return false;     }     if (mode1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN         && mode2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN         && mode1.getRefreshRate() != mode2.getRefreshRate()) {       return false;     }     return true;   }   /**    * Enters full screen mode and changes the display mode. If the specified    * display mode is null or not compatible with this device, or if the    * display mode cannot be changed on this system, the current display mode    * is used.    * <p>    * The display uses a BufferStrategy with 2 buffers.    */   public void setFullScreen(DisplayMode displayMode) {     final JFrame frame = new JFrame();     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     frame.setUndecorated(true);     frame.setIgnoreRepaint(true);     frame.setResizable(false);     device.setFullScreenWindow(frame);     if (displayMode != null && device.isDisplayChangeSupported()) {       try {         device.setDisplayMode(displayMode);       } catch (IllegalArgumentException ex) {       }       // fix for mac os x       frame.setSize(displayMode.getWidth(), displayMode.getHeight());     }     // avoid potential deadlock in 1.4.1_02     try {       EventQueue.invokeAndWait(new Runnable() {         public void run() {           frame.createBufferStrategy(2);         }       });     } catch (InterruptedException ex) {       // ignore     } catch (InvocationTargetException ex) {       // ignore     }   }   /**    * Gets the graphics context for the display. The ScreenManager uses double    * buffering, so applications must call update() to show any graphics drawn.    * <p>    * The application must dispose of the graphics object.    */   public Graphics2D getGraphics() {     Window window = device.getFullScreenWindow();     if (window != null) {       BufferStrategy strategy = window.getBufferStrategy();       return (Graphics2D) strategy.getDrawGraphics();     } else {       return null;     }   }   /**    * Updates the display.    */   public void update() {     Window window = device.getFullScreenWindow();     if (window != null) {       BufferStrategy strategy = window.getBufferStrategy();       if (!strategy.contentsLost()) {         strategy.show();       }     }     // Sync the display on some systems.     // (on Linux, this fixes event queue problems)     Toolkit.getDefaultToolkit().sync();   }   /**    * Returns the window currently used in full screen mode. Returns null if    * the device is not in full screen mode.    */   public JFrame getFullScreenWindow() {     return (JFrame) device.getFullScreenWindow();   }   /**    * Returns the width of the window currently used in full screen mode.    * Returns 0 if the device is not in full screen mode.    */   public int getWidth() {     Window window = device.getFullScreenWindow();     if (window != null) {       return window.getWidth();     } else {       return 0;     }   }   /**    * Returns the height of the window currently used in full screen mode.    * Returns 0 if the device is not in full screen mode.    */   public int getHeight() {     Window window = device.getFullScreenWindow();     if (window != null) {       return window.getHeight();     } else {       return 0;     }   }   /**    * Restores the screen's display mode.    */   public void restoreScreen() {     Window window = device.getFullScreenWindow();     if (window != null) {       window.dispose();     }     device.setFullScreenWindow(null);   }   /**    * Creates an image compatible with the current display.    */   public BufferedImage createCompatibleImage(int w, int h, int transparancy) {     Window window = device.getFullScreenWindow();     if (window != null) {       GraphicsConfiguration gc = window.getGraphicsConfiguration();       return gc.createCompatibleImage(w, h, transparancy);     }     return null;   } } /**  * The InputManager manages input of key and mouse events. Events are mapped to  * GameActions.  */ class InputManager implements KeyListener, MouseListener, MouseMotionListener,     MouseWheelListener {   /**    * An invisible cursor.    */   public static final Cursor INVISIBLE_CURSOR = Toolkit.getDefaultToolkit()       .createCustomCursor(Toolkit.getDefaultToolkit().getImage(""),           new Point(0, 0), "invisible");   // mouse codes   public static final int MOUSE_MOVE_LEFT = 0;   public static final int MOUSE_MOVE_RIGHT = 1;   public static final int MOUSE_MOVE_UP = 2;   public static final int MOUSE_MOVE_DOWN = 3;   public static final int MOUSE_WHEEL_UP = 4;   public static final int MOUSE_WHEEL_DOWN = 5;   public static final int MOUSE_BUTTON_1 = 6;   public static final int MOUSE_BUTTON_2 = 7;   public static final int MOUSE_BUTTON_3 = 8;   private static final int NUM_MOUSE_CODES = 9;   // key codes are defined in java.awt.KeyEvent.   // most of the codes (except for some rare ones like   // "alt graph") are less than 600.   private static final int NUM_KEY_CODES = 600;   private GameAction[] keyActions = new GameAction[NUM_KEY_CODES];   private GameAction[] mouseActions = new GameAction[NUM_MOUSE_CODES];   private Point mouseLocation;   private Point centerLocation;   private Component comp;   private Robot robot;   private boolean isRecentering;   /**    * Creates a new InputManager that listens to input from the specified    * component.    */   public InputManager(Component comp) {     this.comp = comp;     mouseLocation = new Point();     centerLocation = new Point();     // register key and mouse listeners     comp.addKeyListener(this);     comp.addMouseListener(this);     comp.addMouseMotionListener(this);     comp.addMouseWheelListener(this);     // allow input of the TAB key and other keys normally     // used for focus traversal     comp.setFocusTraversalKeysEnabled(false);   }   /**    * Sets the cursor on this InputManager's input component.    */   public void setCursor(Cursor cursor) {     comp.setCursor(cursor);   }   /**    * Sets whether realtive mouse mode is on or not. For relative mouse mode,    * the mouse is "locked" in the center of the screen, and only the changed    * in mouse movement is measured. In normal mode, the mouse is free to move    * about the screen.    */   public void setRelativeMouseMode(boolean mode) {     if (mode == isRelativeMouseMode()) {       return;     }     if (mode) {       try {         robot = new Robot();         recenterMouse();       } catch (AWTException ex) {         // couldn't create robot!         robot = null;       }     } else {       robot = null;     }   }   /**    * Returns whether or not relative mouse mode is on.    */   public boolean isRelativeMouseMode() {     return (robot != null);   }   /**    * Maps a GameAction to a specific key. The key codes are defined in    * java.awt.KeyEvent. If the key already has a GameAction mapped to it, the    * new GameAction overwrites it.    */   public void mapToKey(GameAction gameAction, int keyCode) {     keyActions[keyCode] = gameAction;   }   /**    * Maps a GameAction to a specific mouse action. The mouse codes are defined    * herer in InputManager (MOUSE_MOVE_LEFT, MOUSE_BUTTON_1, etc). If the    * mouse action already has a GameAction mapped to it, the new GameAction    * overwrites it.    */   public void mapToMouse(GameAction gameAction, int mouseCode) {     mouseActions[mouseCode] = gameAction;   }   /**    * Clears all mapped keys and mouse actions to this GameAction.    */   public void clearMap(GameAction gameAction) {     for (int i = 0; i < keyActions.length; i++) {       if (keyActions[i] == gameAction) {         keyActions[i] = null;       }     }     for (int i = 0; i < mouseActions.length; i++) {       if (mouseActions[i] == gameAction) {         mouseActions[i] = null;       }     }     gameAction.reset();   }   /**    * Gets a List of names of the keys and mouse actions mapped to this    * GameAction. Each entry in the List is a String.    */   public List getMaps(GameAction gameCode) {     ArrayList list = new ArrayList();     for (int i = 0; i < keyActions.length; i++) {       if (keyActions[i] == gameCode) {         list.add(getKeyName(i));       }     }     for (int i = 0; i < mouseActions.length; i++) {       if (mouseActions[i] == gameCode) {         list.add(getMouseName(i));       }     }     return list;   }   /**    * Resets all GameActions so they appear like they haven't been pressed.    */   public void resetAllGameActions() {     for (int i = 0; i < keyActions.length; i++) {       if (keyActions[i] != null) {         keyActions[i].reset();       }     }     for (int i = 0; i < mouseActions.length; i++) {       if (mouseActions[i] != null) {         mouseActions[i].reset();       }     }   }   /**    * Gets the name of a key code.    */   public static String getKeyName(int keyCode) {     return KeyEvent.getKeyText(keyCode);   }   /**    * Gets the name of a mouse code.    */   public static String getMouseName(int mouseCode) {     switch (mouseCode) {     case MOUSE_MOVE_LEFT:       return "Mouse Left";     case MOUSE_MOVE_RIGHT:       return "Mouse Right";     case MOUSE_MOVE_UP:       return "Mouse Up";     case MOUSE_MOVE_DOWN:       return "Mouse Down";     case MOUSE_WHEEL_UP:       return "Mouse Wheel Up";     case MOUSE_WHEEL_DOWN:       return "Mouse Wheel Down";     case MOUSE_BUTTON_1:       return "Mouse Button 1";     case MOUSE_BUTTON_2:       return "Mouse Button 2";     case MOUSE_BUTTON_3:       return "Mouse Button 3";     default:       return "Unknown mouse code " + mouseCode;     }   }   /**    * Gets the x position of the mouse.    */   public int getMouseX() {     return mouseLocation.x;   }   /**    * Gets the y position of the mouse.    */   public int getMouseY() {     return mouseLocation.y;   }   /**    * Uses the Robot class to try to postion the mouse in the center of the    * screen.    * <p>    * Note that use of the Robot class may not be available on all platforms.    */   private synchronized void recenterMouse() {     if (robot != null && comp.isShowing()) {       centerLocation.x = comp.getWidth() / 2;       centerLocation.y = comp.getHeight() / 2;       SwingUtilities.convertPointToScreen(centerLocation, comp);       isRecentering = true;       robot.mouseMove(centerLocation.x, centerLocation.y);     }   }   private GameAction getKeyAction(KeyEvent e) {     int keyCode = e.getKeyCode();     if (keyCode < keyActions.length) {       return keyActions[keyCode];     } else {       return null;     }   }   /**    * Gets the mouse code for the button specified in this MouseEvent.    */   public static int getMouseButtonCode(MouseEvent e) {     switch (e.getButton()) {     case MouseEvent.BUTTON1:       return MOUSE_BUTTON_1;     case MouseEvent.BUTTON2:       return MOUSE_BUTTON_2;     case MouseEvent.BUTTON3:       return MOUSE_BUTTON_3;     default:       return -1;     }   }   private GameAction getMouseButtonAction(MouseEvent e) {     int mouseCode = getMouseButtonCode(e);     if (mouseCode != -1) {       return mouseActions[mouseCode];     } else {       return null;     }   }   // from the KeyListener interface   public void keyPressed(KeyEvent e) {     GameAction gameAction = getKeyAction(e);     if (gameAction != null) {       gameAction.press();     }     // make sure the key isn't processed for anything else     e.consume();   }   // from the KeyListener interface   public void keyReleased(KeyEvent e) {     GameAction gameAction = getKeyAction(e);     if (gameAction != null) {       gameAction.release();     }     // make sure the key isn't processed for anything else     e.consume();   }   // from the KeyListener interface   public void keyTyped(KeyEvent e) {     // make sure the key isn't processed for anything else     e.consume();   }   // from the MouseListener interface   public void mousePressed(MouseEvent e) {     GameAction gameAction = getMouseButtonAction(e);     if (gameAction != null) {       gameAction.press();     }   }   // from the MouseListener interface   public void mouseReleased(MouseEvent e) {     GameAction gameAction = getMouseButtonAction(e);     if (gameAction != null) {       gameAction.release();     }   }   // from the MouseListener interface   public void mouseClicked(MouseEvent e) {     // do nothing   }   // from the MouseListener interface   public void mouseEntered(MouseEvent e) {     mouseMoved(e);   }   // from the MouseListener interface   public void mouseExited(MouseEvent e) {     mouseMoved(e);   }   // from the MouseMotionListener interface   public void mouseDragged(MouseEvent e) {     mouseMoved(e);   }   // from the MouseMotionListener interface   public synchronized void mouseMoved(MouseEvent e) {     // this event is from re-centering the mouse - ignore it     if (isRecentering && centerLocation.x == e.getX()         && centerLocation.y == e.getY()) {       isRecentering = false;     } else {       int dx = e.getX() - mouseLocation.x;       int dy = e.getY() - mouseLocation.y;       mouseHelper(MOUSE_MOVE_LEFT, MOUSE_MOVE_RIGHT, dx);       mouseHelper(MOUSE_MOVE_UP, MOUSE_MOVE_DOWN, dy);       if (isRelativeMouseMode()) {         recenterMouse();       }     }     mouseLocation.x = e.getX();     mouseLocation.y = e.getY();   }   // from the MouseWheelListener interface   public void mouseWheelMoved(MouseWheelEvent e) {     mouseHelper(MOUSE_WHEEL_UP, MOUSE_WHEEL_DOWN, e.getWheelRotation());   }   private void mouseHelper(int codeNeg, int codePos, int amount) {     GameAction gameAction;     if (amount < 0) {       gameAction = mouseActions[codeNeg];     } else {       gameAction = mouseActions[codePos];     }     if (gameAction != null) {       gameAction.press(Math.abs(amount));       gameAction.release();     }   } } class Sprite {   private Animation anim;   // position (pixels)   private float x;   private float y;   // velocity (pixels per millisecond)   private float dx;   private float dy;   /**    * Creates a new Sprite object with the specified Animation.    */   public Sprite(Animation anim) {     this.anim = anim;   }   /**    * Updates this Sprite's Animation and its position based on the velocity.    */   public void update(long elapsedTime) {     x += dx * elapsedTime;     y += dy * elapsedTime;     anim.update(elapsedTime);   }   /**    * Gets this Sprite's current x position.    */   public float getX() {     return x;   }   /**    * Gets this Sprite's current y position.    */   public float getY() {     return y;   }   /**    * Sets this Sprite's current x position.    */   public void setX(float x) {     this.x = x;   }   /**    * Sets this Sprite's current y position.    */   public void setY(float y) {     this.y = y;   }   /**    * Gets this Sprite's width, based on the size of the current image.    */   public int getWidth() {     return anim.getImage().getWidth(null);   }   /**    * Gets this Sprite's height, based on the size of the current image.    */   public int getHeight() {     return anim.getImage().getHeight(null);   }   /**    * Gets the horizontal velocity of this Sprite in pixels per millisecond.    */   public float getVelocityX() {     return dx;   }   /**    * Gets the vertical velocity of this Sprite in pixels per millisecond.    */   public float getVelocityY() {     return dy;   }   /**    * Sets the horizontal velocity of this Sprite in pixels per millisecond.    */   public void setVelocityX(float dx) {     this.dx = dx;   }   /**    * Sets the vertical velocity of this Sprite in pixels per millisecond.    */   public void setVelocityY(float dy) {     this.dy = dy;   }   /**    * Gets this Sprite's current image.    */   public Image getImage() {     return anim.getImage();   } } /**  * The Animation class manages a series of images (frames) and the amount of  * time to display each frame.  */ class Animation {   private ArrayList frames;   private int currFrameIndex;   private long animTime;   private long totalDuration;   /**    * Creates a new, empty Animation.    */   public Animation() {     frames = new ArrayList();     totalDuration = 0;     start();   }   /**    * Adds an image to the animation with the specified duration (time to    * display the image).    */   public synchronized void addFrame(Image image, long duration) {     totalDuration += duration;     frames.add(new AnimFrame(image, totalDuration));   }   /**    * Starts this animation over from the beginning.    */   public synchronized void start() {     animTime = 0;     currFrameIndex = 0;   }   /**    * Updates this animation's current image (frame), if neccesary.    */   public synchronized void update(long elapsedTime) {     if (frames.size() > 1) {       animTime += elapsedTime;       if (animTime >= totalDuration) {         animTime = animTime % totalDuration;         currFrameIndex = 0;       }       while (animTime > getFrame(currFrameIndex).endTime) {         currFrameIndex++;       }     }   }   /**    * Gets this Animation's current image. Returns null if this animation has    * no images.    */   public synchronized Image getImage() {     if (frames.size() == 0) {       return null;     } else {       return getFrame(currFrameIndex).image;     }   }   private AnimFrame getFrame(int i) {     return (AnimFrame) frames.get(i);   }   private class AnimFrame {     Image image;     long endTime;     public AnimFrame(Image image, long endTime) {       this.image = image;       this.endTime = endTime;     }   } } /**  * The NullRepaintManager is a RepaintManager that doesn't do any repainting.  * Useful when all the rendering is done manually by the application.  */ class NullRepaintManager extends RepaintManager {   /**    * Installs the NullRepaintManager.    */   public static void install() {     RepaintManager repaintManager = new NullRepaintManager();     repaintManager.setDoubleBufferingEnabled(false);     RepaintManager.setCurrentManager(repaintManager);   }   public void addInvalidComponent(JComponent c) {     // do nothing   }   public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {     // do nothing   }   public void markCompletelyDirty(JComponent c) {     // do nothing   }   public void paintDirtyRegions() {     // do nothing   } }