Tumbleweed game : Game « J2ME « Java






Tumbleweed game

/*
 Title:  J2ME Games With MIDP2
 Authors:  Carol Hamer
 Publisher:  Apress
 ISBN:   1590593820
 */

import javax.microedition.media.*;
import javax.microedition.media.control.*;

import java.util.Random;

import javax.microedition.lcdui.game.*;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * This is the main class of the tumbleweed game.
 * 
 * @author Carol Hamer
 */
public class Jump extends MIDlet implements CommandListener {

  //---------------------------------------------------------
  //   commands

  /**
   * the command to end the game.
   */
  private Command myExitCommand = new Command("Exit", Command.EXIT, 99);

  /**
   * the command to start moving when the game is paused.
   */
  private Command myGoCommand = new Command("Go", Command.SCREEN, 1);

  /**
   * the command to pause the game.
   */
  private Command myPauseCommand = new Command("Pause", Command.SCREEN, 1);

  /**
   * the command to start a new game.
   */
  private Command myNewCommand = new Command("Play Again", Command.SCREEN, 1);

  /**
   * The command to start/pause the music. (This command may appear in a menu)
   */
  private Command myMusicCommand = new Command("Music", Command.SCREEN, 2);

  //---------------------------------------------------------
  //   game object fields

  /**
   * the the canvas that all of the game will be drawn on.
   */
  private JumpCanvas myCanvas;

  //---------------------------------------------------------
  //   thread fields

  /**
   * the thread that advances the cowboy.
   */
  private GameThread myGameThread;

  /**
   * The class that plays music if the user wants.
   */
  //private MusicMaker myMusicMaker;
  private ToneControlMusicMaker myMusicMaker;

  /**
   * The thread tha sets tumbleweeds in motion at random intervals.
   */
  private TumbleweedThread myTumbleweedThread;

  /**
   * if the user has paused the game.
   */
  private boolean myGamePause;

  /**
   * if the game is paused because it is hidden.
   */
  private boolean myHiddenPause;

  //-----------------------------------------------------
  //    initialization and game state changes

  /**
   * Initialize the canvas and the commands.
   */
  public Jump() {
    try {
      myCanvas = new JumpCanvas(this);
      myCanvas.addCommand(myExitCommand);
      myCanvas.addCommand(myMusicCommand);
      myCanvas.addCommand(myPauseCommand);
      myCanvas.setCommandListener(this);
    } catch (Exception e) {
      errorMsg(e);
    }
  }

  /**
   * Switch the command to the play again command.
   */
  void setNewCommand() {
    myCanvas.removeCommand(myPauseCommand);
    myCanvas.removeCommand(myGoCommand);
    myCanvas.addCommand(myNewCommand);
  }

  /**
   * Switch the command to the go command.
   */
  private void setGoCommand() {
    myCanvas.removeCommand(myPauseCommand);
    myCanvas.removeCommand(myNewCommand);
    myCanvas.addCommand(myGoCommand);
  }

  /**
   * Switch the command to the pause command.
   */
  private void setPauseCommand() {
    myCanvas.removeCommand(myNewCommand);
    myCanvas.removeCommand(myGoCommand);
    myCanvas.addCommand(myPauseCommand);
  }

  //----------------------------------------------------------------
  //  implementation of MIDlet
  // these methods may be called by the application management
  // software at any time, so we always check fields for null
  // before calling methods on them.

  /**
   * Start the application.
   */
  public void startApp() throws MIDletStateChangeException {
    try {
      if (myCanvas != null) {
        myCanvas.start();
        myCanvas.flushKeys();
        systemStartThreads();
      }
    } catch (Exception e) {
      errorMsg(e);
    }
  }

  /**
   * stop and throw out the garbage.
   */
  public void destroyApp(boolean unconditional)
      throws MIDletStateChangeException {
    try {
      stopThreads();
      myCanvas = null;
      System.gc();
    } catch (Exception e) {
      errorMsg(e);
    }
  }

  /**
   * request the game to pause. This method is called by the application
   * management software, not in response to a user pausing the game.
   */
  public void pauseApp() {
    try {
      if (myCanvas != null) {
        setGoCommand();
        systemPauseThreads();
      }
    } catch (Exception e) {
      errorMsg(e);
    }
  }

  //----------------------------------------------------------------
  //  implementation of CommandListener

  /*
   * Respond to a command issued on the Canvas. (either reset or exit).
   */
  public void commandAction(Command c, Displayable s) {
    try {
      if (c == myGoCommand) {
        myCanvas.removeCommand(myGoCommand);
        myCanvas.addCommand(myPauseCommand);
        myCanvas.flushKeys();
        userStartThreads();
      } else if (c == myPauseCommand) {
        myCanvas.removeCommand(myPauseCommand);
        myCanvas.addCommand(myGoCommand);
        userPauseThreads();
      } else if (c == myNewCommand) {
        myCanvas.removeCommand(myNewCommand);
        myCanvas.addCommand(myPauseCommand);
        System.gc();
        myCanvas.reset();
        myCanvas.flushKeys();
        myHiddenPause = false;
        myGamePause = false;
        startThreads();
      } else if (c == myMusicCommand) {
        if (myMusicMaker != null) {
          myMusicMaker.toggle();
          myCanvas.repaint();
          myCanvas.serviceRepaints();
        }
      } else if ((c == myExitCommand)/* || (c == Alert.DISMISS_COMMAND)*/) {
        try {
          destroyApp(false);
          notifyDestroyed();
        } catch (MIDletStateChangeException ex) {
        }
      }
    } catch (Exception e) {
      errorMsg(e);
    }
  }

  //-------------------------------------------------------
  //  thread methods

  /**
   * start up all of the game's threads. Creates them if necessary. to be
   * called when the user hits the go command.
   */
  private synchronized void userStartThreads() throws Exception {
    myGamePause = false;
    if (!myHiddenPause) {
      startThreads();
    }
  }

  /**
   * start up all of the game's threads. Creates them if necessary. used by
   * showNotify
   */
  synchronized void systemStartThreads() throws Exception {
    myHiddenPause = false;
    if (!myGamePause) {
      startThreads();
    }
  }

  /**
   * start up all of the game's threads. Creates them if necessary. internal
   * version. note: if this were synchronized, whould it cause deadlock?
   */
  private void startThreads() throws Exception {
    if (myGameThread == null) {
      myGameThread = new GameThread(myCanvas);
      myGameThread.start();
    } else {
      myGameThread.resumeGame();
    }
    if (myTumbleweedThread == null) {
      myTumbleweedThread = new TumbleweedThread(myCanvas);
      myTumbleweedThread.start();
    } else {
      myTumbleweedThread.resumeGame();
    }
    if (myMusicMaker == null) {
      myMusicMaker = new ToneControlMusicMaker();
      //myMusicMaker = new MusicMaker();
      myMusicMaker.start();
    } else {
      myMusicMaker.resumeGame();
    }
  }

  /**
   * Pause all of the threads started by this game. to be called when the user
   * hits the pause command.
   */
  synchronized void userPauseThreads() {
    myGamePause = true;
    pauseThreads();
  }

  /**
   * Pause all of the threads started by this game. used by hideNotify
   */
  void systemPauseThreads() {
    myHiddenPause = true;
    pauseThreads();
  }

  /**
   * start up all of the game's threads. Creates them if necessary. internal
   * version. note: if this were synchronized, whould it cause deadlock?
   */
  private void pauseThreads() {
    if (myGameThread != null) {
      myGameThread.pauseGame();
    }
    if (myTumbleweedThread != null) {
      myTumbleweedThread.pauseGame();
    }
    if (myMusicMaker != null) {
      myMusicMaker.pauseGame();
    }
  }

  /**
   * Stop all of the threads started by this game and delete them as they are
   * no longer usable.
   */
  private synchronized void stopThreads() {
    if (myGameThread != null) {
      myGameThread.requestStop();
    }
    if (myTumbleweedThread != null) {
      myTumbleweedThread.requestStop();
    }
    if (myMusicMaker != null) {
      myMusicMaker.requestStop();
    }
    myGameThread = null;
    myTumbleweedThread = null;
    myMusicMaker = null;
  }

  //-------------------------------------------------------
  //  error methods

  /**
   * Converts an exception to a message and displays the message..
   */
  void errorMsg(Exception e) {
    if (e.getMessage() == null) {
      errorMsg(e.getClass().getName());
    } else {
      errorMsg(e.getClass().getName() + ":" + e.getMessage());
    }
  }

  /**
   * Displays an error message alert if something goes wrong.
   */
  void errorMsg(String msg) {
    Alert errorAlert = new Alert("error", msg, null, AlertType.ERROR);
    errorAlert.setCommandListener(this);
    errorAlert.setTimeout(Alert.FOREVER);
    Display.getDisplay(this).setCurrent(errorAlert);
  }

}

/**
 * This class is the display of the game.
 * 
 * @author Carol Hamer
 */

class JumpCanvas extends javax.microedition.lcdui.game.GameCanvas {

  //---------------------------------------------------------
  //   dimension fields
  //  (constant after initialization)

  /**
   * the height of the green region below the ground.
   */
  static final int GROUND_HEIGHT = 32;

  /**
   * a screen dimension.
   */
  static final int CORNER_X = 0;

  /**
   * a screen dimension.
   */
  static final int CORNER_Y = 0;

  /**
   * a screen dimension.
   */
  static int DISP_WIDTH;

  /**
   * a screen dimension.
   */
  static int DISP_HEIGHT;

  /**
   * a font dimension.
   */
  static int FONT_HEIGHT;

  /**
   * the default font.
   */
  static Font FONT;

  /**
   * a font dimension.
   */
  static int SCORE_WIDTH;

  /**
   * The width of the string that displays the time, saved for placement of
   * time display.
   */
  static int TIME_WIDTH;

  /**
   * color constant
   */
  public static final int BLACK = 0;

  /**
   * color constant
   */
  public static final int WHITE = 0xffffff;

  //---------------------------------------------------------
  //   game object fields

  /**
   * a handle to the display.
   */
  private Display myDisplay;

  /**
   * a handle to the MIDlet object (to keep track of buttons).
   */
  private Jump myJump;

  /**
   * the LayerManager that handles the game graphics.
   */
  private JumpManager myManager;

  /**
   * whether or not the game has ended.
   */
  private boolean myGameOver;

  /**
   * the player's score.
   */
  private int myScore = 0;

  /**
   * How many ticks we start with.
   */
  private int myInitialGameTicks = 950;

  /**
   * this is saved to determine if the time string needs to be recomputed.
   */
  private int myOldGameTicks = myInitialGameTicks;

  /**
   * the number of game ticks that have passed.
   */
  private int myGameTicks = myOldGameTicks;

  /**
   * we save the time string to avoid recreating it unnecessarily.
   */
  private static String myInitialString = "1:00";

  /**
   * we save the time string to avoid recreating it unnecessarily.
   */
  private String myTimeString = myInitialString;

  //-----------------------------------------------------
  //    gets/sets

  /**
   * This is called when the game ends.
   */
  void setGameOver() {
    myGameOver = true;
    myJump.userPauseThreads();
  }

  /**
   * @return a handle to the tumbleweed objects.
   */
  Tumbleweed[] getTumbleweeds() {
    return (myManager.getTumbleweeds());
  }

  //-----------------------------------------------------
  //    initialization and game state changes

  /**
   * Constructor sets the data, performs dimension calculations, and creates
   * the graphical objects.
   */
  public JumpCanvas(Jump midlet) throws Exception {
    super(false);
    myDisplay = Display.getDisplay(midlet);
    myJump = midlet;
    // calculate the dimensions
    DISP_WIDTH = getWidth();
    DISP_HEIGHT = getHeight();
    Display disp = Display.getDisplay(myJump);
    if (disp.numColors() < 256) {
      throw (new Exception("game requires 256 shades"));
    }
    if ((DISP_WIDTH < 150) || (DISP_HEIGHT < 170)) {
      throw (new Exception("Screen too small"));
    }
    if ((DISP_WIDTH > 250) || (DISP_HEIGHT > 250)) {
      throw (new Exception("Screen too large"));
    }
    FONT = getGraphics().getFont();
    FONT_HEIGHT = FONT.getHeight();
    SCORE_WIDTH = FONT.stringWidth("Score: 000");
    TIME_WIDTH = FONT.stringWidth("Time: " + myInitialString);
    if (myManager == null) {
      myManager = new JumpManager(CORNER_X, CORNER_Y + FONT_HEIGHT * 2,
          DISP_WIDTH, DISP_HEIGHT - FONT_HEIGHT * 2 - GROUND_HEIGHT);
    }
  }

  /**
   * This is called as soon as the application begins.
   */
  void start() {
    myGameOver = false;
    myDisplay.setCurrent(this);
    repaint();
  }

  /**
   * sets all variables back to their initial positions.
   */
  void reset() {
    myManager.reset();
    myScore = 0;
    myGameOver = false;
    myGameTicks = myInitialGameTicks;
    myOldGameTicks = myInitialGameTicks;
    repaint();
  }

  /**
   * clears the key states.
   */
  void flushKeys() {
    getKeyStates();
  }

  /**
   * pause the game when it's hidden.
   */
  protected void hideNotify() {
    try {
      myJump.systemPauseThreads();
    } catch (Exception oe) {
      myJump.errorMsg(oe);
    }
  }

  /**
   * When it comes back into view, unpause it.
   */
  protected void showNotify() {
    try {
      myJump.systemStartThreads();
    } catch (Exception oe) {
      myJump.errorMsg(oe);
    }
  }

  //-------------------------------------------------------
  //  graphics methods

  /**
   * paint the game graphic on the screen.
   */
  public void paint(Graphics g) {
    // clear the screen:
    g.setColor(WHITE);
    g.fillRect(CORNER_X, CORNER_Y, DISP_WIDTH, DISP_HEIGHT);
    // color the grass green
    g.setColor(0, 255, 0);
    g.fillRect(CORNER_X, CORNER_Y + DISP_HEIGHT - GROUND_HEIGHT,
        DISP_WIDTH, DISP_HEIGHT);
    // paint the layer manager:
    try {
      myManager.paint(g);
    } catch (Exception e) {
      myJump.errorMsg(e);
    }
    // draw the time and score
    g.setColor(BLACK);
    g.setFont(FONT);
    g.drawString("Score: " + myScore, (DISP_WIDTH - SCORE_WIDTH) / 2,
        DISP_HEIGHT + 5 - GROUND_HEIGHT, g.TOP | g.LEFT);
    g.drawString("Time: " + formatTime(), (DISP_WIDTH - TIME_WIDTH) / 2,
        CORNER_Y + FONT_HEIGHT, g.TOP | g.LEFT);
    // write game over if the game is over
    if (myGameOver) {
      myJump.setNewCommand();
      // clear the top region:
      g.setColor(WHITE);
      g.fillRect(CORNER_X, CORNER_Y, DISP_WIDTH, FONT_HEIGHT * 2 + 1);
      int goWidth = FONT.stringWidth("Game Over");
      g.setColor(BLACK);
      g.setFont(FONT);
      g.drawString("Game Over", (DISP_WIDTH - goWidth) / 2, CORNER_Y
          + FONT_HEIGHT, g.TOP | g.LEFT);
    }
  }

  /**
   * a simple utility to make the number of ticks look like a time...
   */
  public String formatTime() {
    if ((myGameTicks / 16) + 1 != myOldGameTicks) {
      myTimeString = "";
      myOldGameTicks = (myGameTicks / 16) + 1;
      int smallPart = myOldGameTicks % 60;
      int bigPart = myOldGameTicks / 60;
      myTimeString += bigPart + ":";
      if (smallPart / 10 < 1) {
        myTimeString += "0";
      }
      myTimeString += smallPart;
    }
    return (myTimeString);
  }

  //-------------------------------------------------------
  //  game movements

  /**
   * Tell the layer manager to advance the layers and then update the display.
   */
  void advance() {
    myGameTicks--;
    myScore += myManager.advance(myGameTicks);
    if (myGameTicks == 0) {
      setGameOver();
    }
    // paint the display
    try {
      paint(getGraphics());
      flushGraphics();
    } catch (Exception e) {
      myJump.errorMsg(e);
    }
  }

  /**
   * Respond to keystrokes.
   */
  public void checkKeys() {
    if (!myGameOver) {
      int keyState = getKeyStates();
      if ((keyState & LEFT_PRESSED) != 0) {
        myManager.setLeft(true);
      }
      if ((keyState & RIGHT_PRESSED) != 0) {
        myManager.setLeft(false);
      }
      if ((keyState & UP_PRESSED) != 0) {
        myManager.jump();
      }
    }
  }

}

/**
 * This class draws the background grass.
 * 
 * @author Carol Hamer
 */

class Grass extends TiledLayer {

  //---------------------------------------------------------
  //    dimension fields
  //  (constant after initialization)

  /**
   * The width of the square tiles that make up this layer..
   */
  static final int TILE_WIDTH = 20;

  /**
   * This is the order that the frames should be displayed for the animation.
   */
  static final int[] FRAME_SEQUENCE = { 2, 3, 2, 4 };

  /**
   * This gives the number of squares of grass to put along the bottom of the
   * screen.
   */
  static int COLUMNS;

  /**
   * After how many tiles does the background repeat.
   */
  static final int CYCLE = 5;

  /**
   * the fixed Y coordinate of the strip of grass.
   */
  static int TOP_Y;

  //---------------------------------------------------------
  //    instance fields

  /**
   * Which tile we are currently on in the frame sequence.
   */
  private int mySequenceIndex = 0;

  /**
   * The index to use in the static tiles array to get the animated tile..
   */
  private int myAnimatedTileIndex;

  //---------------------------------------------------------
  //   gets / sets

  /**
   * Takes the width of the screen and sets my columns to the correct
   * corresponding number
   */
  static int setColumns(int screenWidth) {
    COLUMNS = ((screenWidth / 20) + 1) * 3;
    return (COLUMNS);
  }

  //---------------------------------------------------------
  //   initialization

  /**
   * constructor initializes the image and animation.
   */
  public Grass() throws Exception {
    super(setColumns(JumpCanvas.DISP_WIDTH), 1, Image
        .createImage("/images/grass.png"), TILE_WIDTH, TILE_WIDTH);
    TOP_Y = JumpManager.DISP_HEIGHT - TILE_WIDTH;
    setPosition(0, TOP_Y);
    myAnimatedTileIndex = createAnimatedTile(2);
    for (int i = 0; i < COLUMNS; i++) {
      if ((i % CYCLE == 0) || (i % CYCLE == 2)) {
        setCell(i, 0, myAnimatedTileIndex);
      } else {
        setCell(i, 0, 1);
      }
    }
  }

  //---------------------------------------------------------
  //   graphics

  /**
   * sets the grass back to its initial position..
   */
  void reset() {
    setPosition(-(TILE_WIDTH * CYCLE), TOP_Y);
    mySequenceIndex = 0;
    setAnimatedTile(myAnimatedTileIndex, FRAME_SEQUENCE[mySequenceIndex]);
  }

  /**
   * alter the background image appropriately for this frame..
   * 
   * @param left
   *            whether or not the player is moving left
   */
  void advance(int tickCount) {
    if (tickCount % 2 == 0) { // slow the animation down a little
      mySequenceIndex++;
      mySequenceIndex %= 4;
      setAnimatedTile(myAnimatedTileIndex,
          FRAME_SEQUENCE[mySequenceIndex]);
    }
  }

}

/**
 * This class contains the loop that keeps the game running.
 * 
 * @author Carol Hamer
 */

class GameThread extends Thread {

  //---------------------------------------------------------
  //   fields

  /**
   * Whether or not the main thread would like this thread to pause.
   */
  private boolean myShouldPause;

  /**
   * Whether or not the main thread would like this thread to stop.
   */
  private boolean myShouldStop;

  /**
   * A handle back to the graphical components.
   */
  private JumpCanvas myJumpCanvas;

  /**
   * The System.time of the last screen refresh, used to regulate refresh
   * speed.
   */
  private long myLastRefreshTime;

  //----------------------------------------------------------
  //   initialization

  /**
   * standard constructor.
   */
  GameThread(JumpCanvas canvas) {
    myJumpCanvas = canvas;
  }

  //----------------------------------------------------------
  //   utilities

  /**
   * Get the amount of time to wait between screen refreshes. Normally we wait
   * only a single millisecond just to give the main thread a chance to update
   * the keystroke info, but this method ensures that the game will not
   * attempt to show too many frames per second.
   */
  private long getWaitTime() {
    long retVal = 1;
    long difference = System.currentTimeMillis() - myLastRefreshTime;
    if (difference < 75) {
      retVal = 75 - difference;
    }
    return (retVal);
  }

  //----------------------------------------------------------
  //   actions

  /**
   * pause the game.
   */
  void pauseGame() {
    myShouldPause = true;
  }

  /**
   * restart the game after a pause.
   */
  synchronized void resumeGame() {
    myShouldPause = false;
    notify();
  }

  /**
   * stops the game.
   */
  synchronized void requestStop() {
    myShouldStop = true;
    notify();
  }

  /**
   * start the game..
   */
  public void run() {
    // flush any keystrokes that occurred before the
    // game started:
    myJumpCanvas.flushKeys();
    myShouldStop = false;
    myShouldPause = false;
    while (true) {
      myLastRefreshTime = System.currentTimeMillis();
      if (myShouldStop) {
        break;
      }
      synchronized (this) {
        while (myShouldPause) {
          try {
            wait();
          } catch (Exception e) {
          }
        }
      }
      myJumpCanvas.checkKeys();
      myJumpCanvas.advance();
      // we do a very short pause to allow the other thread
      // to update the information about which keys are pressed:
      synchronized (this) {
        try {
          wait(getWaitTime());
        } catch (Exception e) {
        }
      }
    }
  }

}
/**
 * This class represents the player.
 * 
 * @author Carol Hamer
 */

class Cowboy extends Sprite {

  //---------------------------------------------------------
  //    dimension fields

  /**
   * The width of the cowboy's bounding rectangle.
   */
  static final int WIDTH = 32;

  /**
   * The height of the cowboy's bounding rectangle.
   */
  static final int HEIGHT = 48;

  /**
   * This is the order that the frames should be displayed for the animation.
   */
  static final int[] FRAME_SEQUENCE = { 3, 2, 1, 2 };

  //---------------------------------------------------------
  //    instance fields

  /**
   * the X coordinate of the cowboy where the cowboy starts the game.
   */
  private int myInitialX;

  /**
   * the Y coordinate of the cowboy when not jumping.
   */
  private int myInitialY;

  /**
   * The jump index that indicates that no jump is currently in progress..
   */
  private int myNoJumpInt = -6;

  /**
   * Where the cowboy is in the jump sequence.
   */
  private int myIsJumping = myNoJumpInt;

  /**
   * If the cowboy is currently jumping, this keeps track of how many points
   * have been scored so far during the jump. This helps the calculation of
   * bonus points since the points being scored depend on how many tumbleweeds
   * are jumped in a single jump.
   */
  private int myScoreThisJump = 0;

  //---------------------------------------------------------
  //   initialization

  /**
   * constructor initializes the image and animation.
   */
  public Cowboy(int initialX, int initialY) throws Exception {
    super(Image.createImage("/images/cowboy.png"), WIDTH, HEIGHT);
    myInitialX = initialX;
    myInitialY = initialY;
    // we define the reference pixel to be in the middle
    // of the cowboy image so that when the cowboy turns
    // from right to left (and vice versa) he does not
    // appear to move to a different location.
    defineReferencePixel(WIDTH / 2, 0);
    setRefPixelPosition(myInitialX, myInitialY);
    setFrameSequence(FRAME_SEQUENCE);
  }

  //---------------------------------------------------------
  //   game methods

  /**
   * If the cowboy has landed on a tumbleweed, we decrease the score.
   */
  int checkCollision(Tumbleweed tumbleweed) {
    int retVal = 0;
    if (collidesWith(tumbleweed, true)) {
      retVal = 1;
      // once the cowboy has collided with the tumbleweed,
      // that tumbleweed is done for now, so we call reset
      // which makes it invisible and ready to be reused.
      tumbleweed.reset();
    }
    return (retVal);
  }

  /**
   * set the cowboy back to its initial position.
   */
  void reset() {
    myIsJumping = myNoJumpInt;
    setRefPixelPosition(myInitialX, myInitialY);
    setFrameSequence(FRAME_SEQUENCE);
    myScoreThisJump = 0;
    // at first the cowboy faces right:
    setTransform(TRANS_NONE);
  }

  //---------------------------------------------------------
  //   graphics

  /**
   * alter the cowboy image appropriately for this frame..
   */
  void advance(int tickCount, boolean left) {
    if (left) {
      // use the mirror image of the cowboy graphic when
      // the cowboy is going towards the left.
      setTransform(TRANS_MIRROR);
      move(-1, 0);
    } else {
      // use the (normal, untransformed) image of the cowboy
      // graphic when the cowboy is going towards the right.
      setTransform(TRANS_NONE);
      move(1, 0);
    }
    // this section advances the animation:
    // every third time through the loop, the cowboy
    // image is changed to the next image in the walking
    // animation sequence:
    if (tickCount % 3 == 0) { // slow the animation down a little
      if (myIsJumping == myNoJumpInt) {
        // if he's not jumping, set the image to the next
        // frame in the walking animation:
        nextFrame();
      } else {
        // if he's jumping, advance the jump:
        // the jump continues for several passes through
        // the main game loop, and myIsJumping keeps track
        // of where we are in the jump:
        myIsJumping++;
        if (myIsJumping < 0) {
          // myIsJumping starts negative, and while it's
          // still negative, the cowboy is going up.
          // here we use a shift to make the cowboy go up a
          // lot in the beginning of the jump, and ascend
          // more and more slowly as he reaches his highest
          // position:
          setRefPixelPosition(getRefPixelX(), getRefPixelY()
              - (2 << (-myIsJumping)));
        } else {
          // once myIsJumping is negative, the cowboy starts
          // going back down until he reaches the end of the
          // jump sequence:
          if (myIsJumping != -myNoJumpInt - 1) {
            setRefPixelPosition(getRefPixelX(), getRefPixelY()
                + (2 << myIsJumping));
          } else {
            // once the jump is done, we reset the cowboy to
            // his non-jumping position:
            myIsJumping = myNoJumpInt;
            setRefPixelPosition(getRefPixelX(), myInitialY);
            // we set the image back to being the walking
            // animation sequence rather than the jumping image:
            setFrameSequence(FRAME_SEQUENCE);
            // myScoreThisJump keeps track of how many points
            // were scored during the current jump (to keep
            // track of the bonus points earned for jumping
            // multiple tumbleweeds). Once the current jump is done,
            // we set it back to zero.
            myScoreThisJump = 0;
          }
        }
      }
    }
  }

  /**
   * makes the cowboy jump.
   */
  void jump() {
    if (myIsJumping == myNoJumpInt) {
      myIsJumping++;
      // switch the cowboy to use the jumping image
      // rather than the walking animation images:
      setFrameSequence(null);
      setFrame(0);
    }
  }

  /**
   * This is called whenever the cowboy clears a tumbleweed so that more
   * points are scored when more tumbleweeds are cleared in a single jump.
   */
  int increaseScoreThisJump() {
    if (myScoreThisJump == 0) {
      myScoreThisJump++;
    } else {
      myScoreThisJump *= 2;
    }
    return (myScoreThisJump);
  }

}

/**
 * This class contains the loop that keeps the game running.
 * 
 * @author Carol Hamer
 */

class TumbleweedThread extends Thread {

  //---------------------------------------------------------
  //   fields

  /**
   * Whether or not the main thread would like this thread to pause.
   */
  private boolean myShouldPause;

  /**
   * Whether or not the main thread would like this thread to stop.
   */
  private boolean myShouldStop;

  /**
   * A handle back to the graphical components.
   */
  private Tumbleweed[] myTumbleweeds;

  /**
   * Random number generator to randomly decide when to appear.
   */
  private Random myRandom = new Random();

  //----------------------------------------------------------
  //   initialization

  /**
   * standard constructor, sets data.
   */
  TumbleweedThread(JumpCanvas canvas) throws Exception {
    myTumbleweeds = canvas.getTumbleweeds();
  }

  //----------------------------------------------------------
  //   actions

  /**
   * pause the thread.
   */
  void pauseGame() {
    myShouldPause = true;
  }

  /**
   * restart the thread after a pause.
   */
  synchronized void resumeGame() {
    myShouldPause = false;
    notify();
  }

  /**
   * stops the thread.
   */
  synchronized void requestStop() {
    myShouldStop = true;
    notify();
  }

  /**
   * start the thread..
   */
  public void run() {
    myShouldStop = false;
    myShouldPause = false;
    while (true) {
      if (myShouldStop) {
        break;
      }
      synchronized (this) {
        while (myShouldPause) {
          try {
            wait();
          } catch (Exception e) {
          }
        }
      }
      // wait a random length of time:
      int waitTime = (1 + getRandomInt(10)) * 100;
      synchronized (this) {
        try {
          wait(waitTime);
        } catch (Exception e) {
        }
      }
      if (!myShouldPause) {
        // randomly select which one to set in motion and
        // tell it to go. If the chosen tumbleweed is
        // currently visible, it will not be affected
        int whichWeed = getRandomInt(myTumbleweeds.length);
        myTumbleweeds[whichWeed].go();
      }
    }
  }

  //----------------------------------------------------------
  //   randomization utilities

  /**
   * Gets a random int between zero and the param upper (exclusive).
   */
  public int getRandomInt(int upper) {
    int retVal = myRandom.nextInt() % upper;
    if (retVal < 0) {
      retVal += upper;
    }
    return (retVal);
  }

}

/**
 * This class represents the tumbleweeds that the player must jump over.
 * 
 * @author Carol Hamer
 */

class Tumbleweed extends Sprite {

  //---------------------------------------------------------
  //   dimension fields

  /**
   * The width of the tumbleweed's bounding square.
   */
  static final int WIDTH = 16;

  //---------------------------------------------------------
  //    instance fields

  /**
   * whether or not this tumbleweed has been jumped over. This is used to
   * calculate the score.
   */
  private boolean myJumpedOver;

  /**
   * whether or not this tumbleweed enters from the left.
   */
  private boolean myLeft;

  /**
   * the Y coordinate of the tumbleweed.
   */
  private int myY;

  /**
   * the leftmost visible pixel.
   */
  private int myCurrentLeftBound;

  /**
   * the rightmost visible pixel.
   */
  private int myCurrentRightBound;

  //---------------------------------------------------------
  //   initialization

  /**
   * constructor initializes the image and animation.
   * 
   * @param left
   *            whether or not this tumbleweed enters from the left.
   */
  public Tumbleweed(boolean left) throws Exception {
    super(Image.createImage("/images/tumbleweed.png"), WIDTH, WIDTH);
    myY = JumpManager.DISP_HEIGHT - WIDTH - 2;
    myLeft = left;
    if (!myLeft) {
      setTransform(TRANS_MIRROR);
    }
    myJumpedOver = false;
    setVisible(false);
  }

  //---------------------------------------------------------
  //   game actions

  /**
   * Set the tumbleweed in motion if it is not currently visible.
   */
  synchronized boolean go() {
    boolean retVal = false;
    if (!isVisible()) {
      retVal = true;
      //System.out.println("Tumbleweed.go-->not visible");
      myJumpedOver = false;
      setVisible(true);
      // set the tumbleweed's position to the point
      // where it just barely appears on the screen
      // to that it can start approaching the cowboy:
      if (myLeft) {
        setRefPixelPosition(myCurrentRightBound, myY);
        move(-1, 0);
      } else {
        setRefPixelPosition(myCurrentLeftBound, myY);
        move(1, 0);
      }
    } else {
      //System.out.println("Tumbleweed.go-->visible");
    }
    return (retVal);
  }

  //---------------------------------------------------------
  //   graphics

  /**
   * move the tumbleweed back to its initial (inactive) state.
   */
  void reset() {
    setVisible(false);
    myJumpedOver = false;
  }

  /**
   * alter the tumbleweed image appropriately for this frame..
   * 
   * @param left
   *            whether or not the player is moving left
   * @return how much the score should change by after this advance.
   */
  synchronized int advance(Cowboy cowboy, int tickCount, boolean left,
      int currentLeftBound, int currentRightBound) {
    int retVal = 0;
    myCurrentLeftBound = currentLeftBound;
    myCurrentRightBound = currentRightBound;
    // if the tumbleweed goes outside of the display
    // region, set it to invisible since it is
    // no longer in use.
    if ((getRefPixelX() - WIDTH >= currentRightBound) && (!myLeft)) {
      setVisible(false);
    }
    if ((getRefPixelX() + WIDTH <= currentLeftBound) && myLeft) {
      setVisible(false);
    }
    if (isVisible()) {
      // when the tumbleweed is active, we advance the
      // rolling animation to the next frame and then
      // move the tumbleweed in the right direction across
      // the screen.
      if (tickCount % 2 == 0) { // slow the animation down a little
        nextFrame();
      }
      if (myLeft) {
        move(-3, 0);
        // if the cowboy just passed the tumbleweed
        // (without colliding with it) we increase the
        // cowboy's score and set myJumpedOver to true
        // so that no further points will be awarded
        // for this tumbleweed until it goes offscreen
        // and then is later reactivated:
        if ((!myJumpedOver) && (getRefPixelX() < cowboy.getRefPixelX())) {
          myJumpedOver = true;
          retVal = cowboy.increaseScoreThisJump();
        }
      } else {
        move(3, 0);
        if ((!myJumpedOver)
            && (getRefPixelX() > cowboy.getRefPixelX()
                + Cowboy.WIDTH)) {
          myJumpedOver = true;
          retVal = cowboy.increaseScoreThisJump();
        }
      }
    }
    return (retVal);
  }

}

/**
 * This is the class that plays a little tune while you play the game. This
 * version uses the Player and Control interfaces.
 * 
 * @author Carol Hamer
 */

class ToneControlMusicMaker implements PlayerListener {

  //---------------------------------------------------------
  //   fields

  /**
   * The player object that plays the tune.
   */
  private Player myPlayer;

  /**
   * Whether or not the player wants to pause the music.
   */
  private boolean myShouldPause;

  /**
   * Whether or not the system wants to pause the music.
   */
  private boolean myGamePause;

  /**
   * The tune played by the game, stored as an array of bytes in BNF notation.
   */
  private byte[] myTune = {
  // first set the version
      ToneControl.VERSION, 1,
      // set the tempo
      ToneControl.TEMPO, 30,
      // define the first line of the song
      ToneControl.BLOCK_START, 0, 69, 8, 69, 8, 69, 8, 71, 8, 73, 16, 71,
      16, 69, 8, 73, 8, 71, 8, 71, 8, 69, 32, ToneControl.BLOCK_END, 0,
      // define the other line of the song
      ToneControl.BLOCK_START, 1, 71, 8, 71, 8, 71, 8, 71, 8, 66, 16, 66,
      16, 71, 8, 69, 8, 68, 8, 66, 8, 64, 32, ToneControl.BLOCK_END, 1,
      // play the song
      ToneControl.PLAY_BLOCK, 0, ToneControl.PLAY_BLOCK, 0,
      ToneControl.PLAY_BLOCK, 1, ToneControl.PLAY_BLOCK, 0, };

  //----------------------------------------------------------
  //   actions

  /**
   * call this when the game pauses. This method does not affect the field
   * myShouldPause because this method is called only when the system pauses
   * the music, not when the player pauses the music.
   */
  void pauseGame() {
    try {
      myGamePause = true;
      myPlayer.stop();
      // when the application pauses the game, resources
      // are supposed to be released, so we close the
      // player and throw it away.
      myPlayer.close();
      myPlayer = null;
    } catch (Exception e) {
      // the music isn't necessary, so we ignore exceptions.
    }
  }

  /**
   * call this when the game resumes. This method does not affect the field
   * myShouldPause because this method is called only when the system reusmes
   * the music, not when the player pauses the music.
   */
  synchronized void resumeGame() {
    try {
      myGamePause = false;
      if (!myShouldPause) {
        // if the player is null, we create a new one.
        if (myPlayer == null) {
          start();
        }
        // start the music.
        myPlayer.start();
      }
    } catch (Exception e) {
      // the music isn't necessary, so we ignore exceptions.
    }
  }

  /**
   * toggle the music. (pause it if it's going, start it again if it's
   * paused).
   */
  synchronized void toggle() {
    try {
      myShouldPause = !myShouldPause;
      if (myShouldPause) {
        if (myPlayer != null) {
          myPlayer.stop();
        }
      } else if (!myGamePause) {
        // if the player is null, we create a new one.
        if (myPlayer == null) {
          start();
        }
        // start the music.
        myPlayer.start();
      }
    } catch (Exception e) {
      // the music isn't necessary, so we ignore exceptions.
    }
  }

  /**
   * stops the music.
   */
  synchronized void requestStop() {
    try {
      myPlayer.stop();
      // this is called when the game is over, to we close
      // up the player to release the resources.
      myPlayer.close();
    } catch (Exception e) {
      // the music isn't necessary, so we ignore exceptions.
    }
  }

  //----------------------------------------------------------
  //   initialization

  /**
   * start the music.. Here the method is "start" instead of "run" because it
   * is not necessary to create a thread for the Player. the Player runs on
   * its own thread.
   */
  public void start() {
    ToneControl control = null;
    try {
      myPlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
      // do the preliminary set-up:
      myPlayer.realize();
      // set a listener to listen for the end of the tune:
      myPlayer.addPlayerListener(this);
      // get the ToneControl object in order to set the tune data:
      control = (ToneControl) myPlayer.getControl("ToneControl");
      control.setSequence(myTune);
      // set the volume to the highest possible volume:
      VolumeControl vc = (VolumeControl) myPlayer
          .getControl("VolumeControl");
      vc.setLevel(100);
    } catch (Exception e) {
      // the music isn't necessary, so we ignore exceptions.
    }
  }

  //----------------------------------------------------------
  //   implementation of PlayerListener

  /**
   * If we reach the end of the song, play it again...
   */
  public void playerUpdate(Player player, String event, Object eventData) {
    if (event.equals(PlayerListener.END_OF_MEDIA)) {
      if ((!myShouldPause) && (!myGamePause)) {
        try {
          myPlayer.start();
        } catch (Exception e) {
          // the music isn't necessary, so we ignore exceptions.
        }
      }
    }
  }

}
/**
 * This is the class that plays a little tune while you play the game.
 * 
 * @author Carol Hamer
 */

class MusicMaker extends Thread {

  //---------------------------------------------------------
  //   fields

  /**
   * Whether or not the main thread would like this thread to stop.
   */
  public static final int NOTE_LENGTH = 250;

  /**
   * Whether or not the main thread would like this thread to pause.
   */
  private boolean myShouldPause;

  /**
   * If the whole game is paused, we pause the music too..
   */
  private boolean myGamePause;

  /**
   * Whether or not the main thread would like this thread to stop.
   */
  private static boolean myShouldStop;

  /**
   * The tune played by the game, stored as an array of notes and durations.
   * 
   * NOTE: 69 is A. To get other notes, just add or subtract their difference
   * from A on the keyboard including the black keys in the calculation. See
   * the scales below for an idea.
   *  
   */
  private byte[][] myTune = { { 69, 1 }, { 69, 1 }, { 69, 1 }, { 71, 1 },
      { 73, 2 }, { 71, 2 }, { 69, 1 }, { 73, 1 }, { 71, 1 }, { 71, 1 },
      { 69, 4 }, { 69, 1 }, { 69, 1 }, { 69, 1 }, { 71, 1 }, { 73, 2 },
      { 71, 2 }, { 69, 1 }, { 73, 1 }, { 71, 1 }, { 71, 1 }, { 69, 4 },
      { 71, 1 }, { 71, 1 }, { 71, 1 }, { 71, 1 }, { 66, 2 }, { 66, 2 },
      { 71, 1 }, { 69, 1 }, { 68, 1 }, { 66, 1 }, { 64, 4 }, { 69, 1 },
      { 69, 1 }, { 69, 1 }, { 71, 1 }, { 73, 2 }, { 71, 2 }, { 69, 1 },
      { 73, 1 }, { 71, 1 }, { 71, 1 }, { 69, 4 } };

  /**
   * An example "tune" that is just a scale.. not used.
   */
  private byte[][] myScale = { { 69, 1 }, { 71, 1 }, { 73, 1 }, { 74, 1 },
      { 76, 1 }, { 78, 1 }, { 80, 1 }, { 81, 1 } };

  /**
   * An example "tune" that is just a scale.. not used.
   */
  private byte[][] myScale2 = { { 57, 1 }, { 59, 1 }, { 61, 1 }, { 62, 1 },
      { 64, 1 }, { 66, 1 }, { 68, 1 }, { 69, 1 } };

  //----------------------------------------------------------
  //   actions

  /**
   * call this when the game pauses.
   */
  void pauseGame() {
    myGamePause = true;
  }

  /**
   * call this when the game resumes.
   */
  synchronized void resumeGame() {
    myGamePause = false;
    this.notify();
  }

  /**
   * toggle the music. (pause it if it's going, start it again if it's
   * paused).
   */
  synchronized void toggle() {
    myShouldPause = !myShouldPause;
    this.notify();
  }

  /**
   * stops the music.
   */
  synchronized void requestStop() {
    myShouldStop = true;
    this.notify();
  }

  /**
   * start the music..
   */
  public void run() {
    myShouldStop = false;
    myShouldPause = true;
    myGamePause = false;
    int counter = 0;
    while (true) {
      if (myShouldStop) {
        break;
      }
      synchronized (this) {
        while ((myShouldPause) || (myGamePause)) {
          try {
            wait();
          } catch (Exception e) {
          }
        }
      }
      try {
        Manager.playTone(myTune[counter][0], myTune[counter][1]
            * NOTE_LENGTH, 50);
      } catch (Exception e) {
        // the music isn't necessary, so we ignore exceptions.
      }
      synchronized (this) {
        try {
          wait(myTune[counter][1] * NOTE_LENGTH);
        } catch (Exception e) {
        }
      }
      counter++;
      if (counter >= myTune.length) {
        counter = 0;
      }
    }
  }

}
/**
 * This handles the graphics objects.
 * 
 * @author Carol Hamer
 */

class JumpManager extends javax.microedition.lcdui.game.LayerManager {

  //---------------------------------------------------------
  //   dimension fields
  //  (constant after initialization)

  /**
   * The x-coordinate of the place on the game canvas where the LayerManager
   * window should appear, in terms of the coordiantes of the game canvas.
   */
  static int CANVAS_X;

  /**
   * The y-coordinate of the place on the game canvas where the LayerManager
   * window should appear, in terms of the coordiantes of the game canvas.
   */
  static int CANVAS_Y;

  /**
   * The width of the display window.
   */
  static int DISP_WIDTH;

  /**
   * The height of this object's graphical region. This is the same as the
   * height of the visible part because in this game the layer manager's
   * visible part scrolls only left and right but not up and down.
   */
  static int DISP_HEIGHT;

  //   game object fields

  // the player's object.
  private Cowboy myCowboy;

  /**
   * the tumbleweeds that enter from the left.
   */
  private Tumbleweed[] myLeftTumbleweeds;

  /**
   * the tumbleweeds that enter from the right.
   */
  private Tumbleweed[] myRightTumbleweeds;

  /**
   * the object representing the grass in the background..
   */
  private Grass myGrass;

  /**
   * Whether or not the player is currently going left.
   */
  private boolean myLeft;

  /**
   * The leftmost x-coordinate that should be visible on the screen in terms
   * of this objects internal coordinates.
   */
  private int myCurrentLeftX;

  //-----------------------------------------------------
  //    gets/sets

  /**
   * This tells the player to turn left or right.
   * 
   * @param left
   *            whether or not the turn is towards the left..
   */
  void setLeft(boolean left) {
    myLeft = left;
  }

  /**
   * @return a handle to the tumbleweed objects.
   */
  Tumbleweed[] getTumbleweeds() {
    Tumbleweed[] retArray = new Tumbleweed[myLeftTumbleweeds.length
        + myRightTumbleweeds.length];
    for (int i = 0; i < myLeftTumbleweeds.length; i++) {
      retArray[i] = myLeftTumbleweeds[i];
    }
    for (int i = 0; i < myRightTumbleweeds.length; i++) {
      retArray[i + myLeftTumbleweeds.length] = myRightTumbleweeds[i];
    }
    return (retArray);
  }

  //-----------------------------------------------------
  //    initialization and game state changes

  /**
   * Constructor sets the data and constructs the graphical objects..
   * 
   * @param x
   *            The x-coordinate of the place on the game canvas where the
   *            LayerManager window should appear, in terms of the coordiantes
   *            of the game canvas.
   * @param y
   *            The y-coordinate of the place on the game canvas where the
   *            LayerManager window should appear, in terms of the coordiantes
   *            of the game canvas.
   * @param width
   *            the width of the region that is to be occupied by the
   *            LayoutManager.
   * @param height
   *            the height of the region that is to be occupied by the
   *            LayoutManager.
   */
  public JumpManager(int x, int y, int width, int height) throws Exception {
    CANVAS_X = x;
    CANVAS_Y = y;
    DISP_WIDTH = width;
    DISP_HEIGHT = height;
    myCurrentLeftX = Grass.CYCLE * Grass.TILE_WIDTH;
    setViewWindow(0, 0, DISP_WIDTH, DISP_HEIGHT);
    // create the player:
    if (myCowboy == null) {
      myCowboy = new Cowboy(myCurrentLeftX + DISP_WIDTH / 2, DISP_HEIGHT
          - Cowboy.HEIGHT - 2);
      append(myCowboy);
    }
    // create the tumbleweeds to jump over:
    if (myLeftTumbleweeds == null) {
      myLeftTumbleweeds = new Tumbleweed[2];
      for (int i = 0; i < myLeftTumbleweeds.length; i++) {
        myLeftTumbleweeds[i] = new Tumbleweed(true);
        append(myLeftTumbleweeds[i]);
      }
    }
    if (myRightTumbleweeds == null) {
      myRightTumbleweeds = new Tumbleweed[2];
      for (int i = 0; i < myRightTumbleweeds.length; i++) {
        myRightTumbleweeds[i] = new Tumbleweed(false);
        append(myRightTumbleweeds[i]);
      }
    }
    // create the background object:
    if (myGrass == null) {
      myGrass = new Grass();
      append(myGrass);
    }
  }

  /**
   * sets all variables back to their initial positions.
   */
  void reset() {
    if (myGrass != null) {
      myGrass.reset();
    }
    if (myCowboy != null) {
      myCowboy.reset();
    }
    if (myLeftTumbleweeds != null) {
      for (int i = 0; i < myLeftTumbleweeds.length; i++) {
        myLeftTumbleweeds[i].reset();
      }
    }
    if (myRightTumbleweeds != null) {
      for (int i = 0; i < myRightTumbleweeds.length; i++) {
        myRightTumbleweeds[i].reset();
      }
    }
    myLeft = false;
    myCurrentLeftX = Grass.CYCLE * Grass.TILE_WIDTH;
  }

  //-------------------------------------------------------
  //  graphics methods

  /**
   * paint the game graphic on the screen.
   */
  public void paint(Graphics g) {
    setViewWindow(myCurrentLeftX, 0, DISP_WIDTH, DISP_HEIGHT);
    paint(g, CANVAS_X, CANVAS_Y);
  }

  /**
   * If the cowboy gets to the end of the graphical region, move all of the
   * pieces so that the screen appears to wrap.
   */
  private void wrap() {
    if (myCurrentLeftX % (Grass.TILE_WIDTH * Grass.CYCLE) == 0) {
      if (myLeft) {
        myCowboy.move(Grass.TILE_WIDTH * Grass.CYCLE, 0);
        myCurrentLeftX += (Grass.TILE_WIDTH * Grass.CYCLE);
        for (int i = 0; i < myLeftTumbleweeds.length; i++) {
          myLeftTumbleweeds[i]
              .move(Grass.TILE_WIDTH * Grass.CYCLE, 0);
        }
        for (int i = 0; i < myRightTumbleweeds.length; i++) {
          myRightTumbleweeds[i].move(Grass.TILE_WIDTH * Grass.CYCLE,
              0);
        }
      } else {
        myCowboy.move(-(Grass.TILE_WIDTH * Grass.CYCLE), 0);
        myCurrentLeftX -= (Grass.TILE_WIDTH * Grass.CYCLE);
        for (int i = 0; i < myLeftTumbleweeds.length; i++) {
          myLeftTumbleweeds[i].move(-Grass.TILE_WIDTH * Grass.CYCLE,
              0);
        }
        for (int i = 0; i < myRightTumbleweeds.length; i++) {
          myRightTumbleweeds[i].move(-Grass.TILE_WIDTH * Grass.CYCLE,
              0);
        }
      }
    }
  }

  //-------------------------------------------------------
  //  game movements

  /**
   * Tell all of the moving components to advance.
   * 
   * @param gameTicks
   *            the remainaing number of times that the main loop of the game
   *            will be executed before the game ends.
   * @return the change in the score after the pieces have advanced.
   */
  int advance(int gameTicks) {
    int retVal = 0;
    // first we move the view window
    // (so we are showing a slightly different view of
    // the manager's graphical area.)
    if (myLeft) {
      myCurrentLeftX--;
    } else {
      myCurrentLeftX++;
    }
    // now we tell the game objects to move accordingly.
    myGrass.advance(gameTicks);
    myCowboy.advance(gameTicks, myLeft);
    for (int i = 0; i < myLeftTumbleweeds.length; i++) {
      retVal += myLeftTumbleweeds[i].advance(myCowboy, gameTicks, myLeft,
          myCurrentLeftX, myCurrentLeftX + DISP_WIDTH);
      retVal -= myCowboy.checkCollision(myLeftTumbleweeds[i]);
    }
    for (int i = 0; i < myLeftTumbleweeds.length; i++) {
      retVal += myRightTumbleweeds[i].advance(myCowboy, gameTicks,
          myLeft, myCurrentLeftX, myCurrentLeftX + DISP_WIDTH);
      retVal -= myCowboy.checkCollision(myRightTumbleweeds[i]);
    }
    // now we check if we have reached an edge of the viewable
    // area, and if so we move the view area and all of the
    // game objects so that the game appears to wrap.
    wrap();
    return (retVal);
  }

  /**
   * Tell the cowboy to jump..
   */
  void jump() {
    myCowboy.jump();
  }

}


           
       








Related examples in the same category

1.Maze gameMaze game
2.Checkers gameCheckers game
3.Game Action ExampleGame Action Example
4.Game Key EventGame Key Event
5.Sweep GameSweep Game
6.SweepSweep
7.Dungeon game
8.Canvas for processing game actionsCanvas for processing game actions