advertisement
javaboutique
Search Tips
Articles  |   Tutorials  |   Reviews  |   Tools  |   by Category  |   by Date  |   by Name  |   Submit  |   Source  |   Forums  |  
javaboutique
Browse DevX


Partners & Affiliates











advertisement

SnakePit


/************************************************************************************************

SnakePit.java

  Usage:

  <applet code="SnakePit.class" width=625 height=430></applet>

  Keyboard Controls:

  S           - Start Game
  P           - Pause Game
  M           - Mute Sound
  Cursor Keys - Change Direction

************************************************************************************************/

import java.awt.*;
import java.net.*;
import java.util.*;
import java.applet.Applet;
import java.applet.AudioClip;

/************************************************************************************************
  Main applet code.
************************************************************************************************/

public class SnakePit extends Applet implements Runnable {

  // Thread control variables.

  Thread loopThread;
  Thread loadThread;

  // Constants

  static final int MAX_DELAY  = 75;    // Milliseconds between screen updates.
  static final int MIN_DELAY  = 50;
  static final int DELAY_INCR =  5;

  static final int GRID_WIDTH  = 39;    // Size of playing field.
  static final int GRID_HEIGHT = 25;
  static final int GRID_SIZE   = 16;    // Grid size in pixels.

  static final int NUM_LEVELS = 5;    // Number of levels.
  static final int NUM_MICE   = 6;    // Number of active mice.
  static final int NUM_LIVES  = 3;    // Starting number of lives.

  static final int INIT  = 1;    // Game states.
  static final int PLAY  = 2;
  static final int LEVEL = 3;
  static final int END   = 4;
  static final int OVER  = 5;

  static final int END_COUNT   = 30;    // Counter values.
  static final int LEVEL_COUNT = 40;

  static final int TYPE_MASK  = 0x00FF0000;    // Grid cell types.
  static final int EMPTY      = 0x00000000;
  static final int BLOCK      = 0x00010000;
  static final int SNAKE      = 0x00020000;
  static final int MOUSE      = 0x00030000;
  static final int KEY        = 0x00040000;

  static final int DIR_MASK   = 0x0000FF00;    // Grid cell directions.
  static final int NONE       = 0x00000000;
  static final int LEFT       = 0x00000100;
  static final int RIGHT      = 0x00000200;
  static final int UP         = 0x00000300;
  static final int DOWN       = 0x00000400;

  static final int SHAPE_MASK = 0x000000FF;    // Grid cell shapes.
  static final int SQUARE     = 0x00000000;
  static final int SNAKEHEAD  = 0x00000001;
  static final int SNAKEBODY  = 0x00000002;
  static final int SNAKEELB1  = 0x00000003;
  static final int SNAKEELB2  = 0x00000004;
  static final int SNAKETAIL  = 0x00000005;
  static final int MOUSEBODY  = 0x00000006;
  static final int KEYSHAPE   = 0x00000007;

  static final int MOUSE_POINTS =  10;    // Scoring values.
  static final int LEVEL_POINTS = 200;
  static final int EXTRA_LIFE   = 500;

  // Sizing data.

  int width;
  int height;

  // Game data.

  int     score;         // Scoring data.
  int     highScore;
  int     lives;
  int     extraLife;

  int     level;         // Level data.
  int     levelTotal;
  int     miceNeeded;
  int     miceEaten;
  int     delay;

  int[][] grid;          // Playing field.

  Point[] snake;         // Snake data.
  int     headPtr;
  int     tailPtr;
  int     direction;
  int     lastDirection;
  boolean lockKeys;

  Point[] mouse;         // Mouse data.

  Point   key;           // Key data.
  boolean keyActive;

  int     gameState;     // Game state data.
  int     levelCounter;
  int     endCounter;
  boolean paused;

  // Screen colors.

  Color bgColor    = Color.black;
  Color fgColor    = Color.white;
  Color blockColor = new Color(0, 0, 153);
  Color fieldColor = new Color(204, 153, 102);
  Color snakeColor = new Color(0, 153, 0);
  Color mouseColor = Color.gray;
  Color keyColor   = new Color(204, 102, 102);

  // Basic shapes.

  Polygon snakeHead;
  Polygon snakeBody;
  Polygon snakeTail;
  Polygon snakeElb1;
  Polygon snakeElb2;
  Polygon mouseBody;
  Polygon keyShape;

  // Sound data.

  boolean   loaded = false;
  boolean   sound;
  AudioClip bonkSound;
  AudioClip munchSound;
  AudioClip squeakSound;
  AudioClip chimeSound;
  AudioClip advanceSound;

  // Values for the offscreen image.

  Dimension offDimension;
  Image     offImage;
  Graphics offGraphics;

  // Font data.

  Font font = new Font("Helvetica", Font.BOLD, 12);
  FontMetrics fm;
  int fontWidth;
  int fontHeight;

  // Applet information.

  public String getAppletInfo() {

    return("Snake Pit, Copyright 1998 by Mike Hall.");
  }

  public void init() {

    Graphics g;
    int i;

    // Take credit.

    System.out.println("Snake Pit, Copyright 1998 by Mike Hall.");

    // Set font data.

    g = getGraphics();
    g.setFont(font);
    fm = g.getFontMetrics();
    fontWidth = fm.getMaxAdvance();
    fontHeight = fm.getHeight();

    // Define the playing grid.

    grid = new int[GRID_WIDTH][GRID_HEIGHT];

    // Initialize basic shapes.

    snakeHead = new Polygon();
    snakeHead.addPoint(4, 15);
    snakeHead.addPoint(3, 14);
    snakeHead.addPoint(1, 12);
    snakeHead.addPoint(1, 8);
    snakeHead.addPoint(3, 6);
    snakeHead.addPoint(3, 4);
    snakeHead.addPoint(6, 1);
    snakeHead.addPoint(9, 1);
    snakeHead.addPoint(12, 4);
    snakeHead.addPoint(12, 6);
    snakeHead.addPoint(14, 8);
    snakeHead.addPoint(14, 12);
    snakeHead.addPoint(12, 14);
    snakeHead.addPoint(11, 15);

    snakeBody = new Polygon();
    snakeBody.addPoint(11, 0);
    snakeBody.addPoint(11, 15);
    snakeBody.addPoint(4, 15);
    snakeBody.addPoint(4, 0);

    snakeElb1 = new Polygon();
    snakeElb1.addPoint(11, 0);
    snakeElb1.addPoint(11, 4);
    snakeElb1.addPoint(15, 4);
    snakeElb1.addPoint(15, 11);
    snakeElb1.addPoint(7, 11);
    snakeElb1.addPoint(4, 8);
    snakeElb1.addPoint(4, 0);

    snakeElb2 = mirror(snakeElb1);

    snakeTail = new Polygon();
    snakeTail.addPoint(11, 0);
    snakeTail.addPoint(8, 15);
    snakeTail.addPoint(7, 15);
    snakeTail.addPoint(4, 0);

    mouseBody = new Polygon();
    mouseBody.addPoint(8, 1);
    mouseBody.addPoint(12, 5);
    mouseBody.addPoint(12, 6);
    mouseBody.addPoint(10, 7);
    mouseBody.addPoint(12, 9);
    mouseBody.addPoint(12, 12);
    mouseBody.addPoint(10, 14);
    mouseBody.addPoint(5, 14);
    mouseBody.addPoint(3, 12);
    mouseBody.addPoint(3, 9);
    mouseBody.addPoint(5, 7);
    mouseBody.addPoint(3, 6);
    mouseBody.addPoint(3, 5);
    mouseBody.addPoint(7, 1);

    keyShape = new Polygon();
    keyShape.addPoint(1, 6);
    keyShape.addPoint(7, 6);
    keyShape.addPoint(9, 4);
    keyShape.addPoint(13, 4);
    keyShape.addPoint(15, 6);
    keyShape.addPoint(15, 10);
    keyShape.addPoint(13, 12);
    keyShape.addPoint(9, 12);
    keyShape.addPoint(7, 10);
    keyShape.addPoint(3, 10);
    keyShape.addPoint(3, 11);
    keyShape.addPoint(0, 11);
    keyShape.addPoint(0, 7);

    // Initialize data.

    highScore = 0;
    sound = true;
    snake = new Point[GRID_WIDTH * GRID_HEIGHT];
    for (i = 0; i < snake.length; i++)
      snake[i] = new Point(-1, -1);
    mouse = new Point[NUM_MICE];
    for (i = 0; i < NUM_MICE; i++)
      mouse[i] = new Point(-1, -1);
    key = new Point(-1, -1);
    lockKeys = false;
    initGame();
    endGame();
    for (i = 0; i < NUM_MICE; i++)
      killMouse(i);
    gameState = INIT;
  }

  public void initGame() {

    // Initialize game data.

    score = 0;
    lives = NUM_LIVES;
    level = 0;
    levelTotal = 0;
    extraLife = EXTRA_LIFE;
    delay = MAX_DELAY;
    paused = false;
    initLevel();
  }

  public void endGame() {

    gameState = OVER;
  }

  public void initLevel() {

    int i;

    // Advance level. Once we have gone thru each, start at the beginning and
    // increase speed.

    level++;
    if (level > NUM_LEVELS) {
      level = 1;
      if (delay > MIN_DELAY)
        delay -= DELAY_INCR;
    }

    // Level total for display.

    levelTotal++;

    // Initialize game data.

    initBlocks();
    initSnake();
    for (i = 0; i < NUM_MICE; i++)
      initMouse(i);
    miceEaten = 0;
    miceNeeded = 3 * (NUM_MICE + NUM_LEVELS - level);
    keyActive = false;
    gameState = PLAY;
  }

  public void endLevel() {

    // Start counter to pause before changing level.

    gameState = LEVEL;
    levelCounter = LEVEL_COUNT;
  }


  public void initLife() {

    // Create a new snake.

    killSnake();
    initSnake();
    gameState = PLAY;
  }

  public void endLife() {

    // Start counter to pause before starting a new snake.

    gameState = END;
    endCounter = END_COUNT;
  }

  public void start() {

    if (loopThread == null) {
      loopThread = new Thread(this);
      loopThread.start();
    }
    if (!loaded && loadThread == null) {
      loadThread = new Thread(this);
      loadThread.start();
    }
  }

  public void stop() {

    if (loopThread != null) {
      loopThread.stop();
      loopThread = null;
    }
    if (loadThread != null) {
      loadThread.stop();
      loadThread = null;
    }
  }

  public void run() {

    int i;
    long startTime;

    // Lower this thread's priority and get the current time.

    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    startTime = System.currentTimeMillis();

    // Run thread for loading sounds.

    if (!loaded && Thread.currentThread() == loadThread) {
      loadSounds();
      loaded = true;
      loadThread.stop();
    }

    // This is the main loop.

    while (Thread.currentThread() == loopThread) {

      if (!paused) {

        // Move snake and mice.

        if (gameState == PLAY) {
          moveSnake();
          for (i = 0; i < NUM_MICE; i++)
            moveMouse(i);
        }

        // Check the score and advance high score if necessary.

        if (score > highScore)
          highScore = score;

        // Add an extra life if score is high enough.

        if (score >= extraLife) {
          lives++;
          extraLife += EXTRA_LIFE;
        }

        // See if the snake was killed. If any lives are left, continue with
        // a new one.

        if (gameState == END && --endCounter < 0)
          if (--lives == 0)
            endGame();
          else
            initLife();

        // If enough mice have been eaten, show the key.

        if (gameState == PLAY && miceEaten == miceNeeded && !keyActive) {
          if (loaded && sound)
            chimeSound.play();
          initKey();
        }

        // If level was completed, go to the next one when the counter finishes.

        if (gameState == LEVEL && --levelCounter < 0)
          initLevel();
      }

      // Update the screen and set the timer for the next loop.

      repaint();
      try {
        if (gameState == PLAY)
          startTime += delay;
        else
          startTime += MIN_DELAY;
        Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));
      }
      catch (InterruptedException e) {
        break;
      }
    }
  }

  public void loadSounds() {

    // Load all sound clips by playing and immediately stopping them.

    try {
      bonkSound    = getAudioClip(new URL(getDocumentBase(), "bonk.au"));
      munchSound   = getAudioClip(new URL(getDocumentBase(), "munch.au"));
      squeakSound  = getAudioClip(new URL(getDocumentBase(), "squeak.au"));
      chimeSound   = getAudioClip(new URL(getDocumentBase(), "chime.au"));
      advanceSound = getAudioClip(new URL(getDocumentBase(), "advance.au"));
    }
    catch (MalformedURLException e) {}

    bonkSound.play();    bonkSound.stop();
    munchSound.play();   munchSound.stop();
    squeakSound.play();  squeakSound.stop();
    chimeSound.play();   chimeSound.stop();
    advanceSound.play(); advanceSound.stop();
  }

  public boolean keyDown(Event e, int key) {

    // Check if any cursor keys have been pressed and set direction but don't
    // allow a reversal of direction.

    if (!paused && !lockKeys) {
      if (key == Event.LEFT && lastDirection != RIGHT)
        direction = LEFT;
      else if (key == Event.RIGHT && lastDirection != LEFT && lastDirection != NONE)
        direction = RIGHT;
      else if (key == Event.UP && lastDirection != DOWN)
        direction = UP;
      else if (key == Event.DOWN && lastDirection != UP)
        direction = DOWN;
    }

    // 'M' key: toggle sound.

    if (key == 109) {
      if (sound) {
        bonkSound.stop();
        munchSound.stop();
        squeakSound.stop();
        chimeSound.stop();
        advanceSound.stop();
      }
      sound = !sound;
    }

    // 'P' key: toggle pause mode.

    if (key == 112)
      paused = !paused;

    // 'S' key: start the game, if not already in progress.

    if (loaded && key == 115 && (gameState == INIT || gameState == OVER))
      initGame();

    return true;
  }

  public void initBlocks() {

    int i, j;

    // Clear the grid.

    for (i = 0; i < GRID_WIDTH; i++)
      for (j = 0; j < GRID_HEIGHT; j++)
        grid[i][j] = EMPTY | NONE | SQUARE;

    // Add outer walls.

    for (i = 0; i < GRID_WIDTH; i++) {
      grid[i][0] = BLOCK | NONE | SQUARE;
      grid[i][GRID_HEIGHT - 1] = BLOCK | NONE | SQUARE;
    }
    for (j = 1; j < GRID_HEIGHT - 1; j++) {
      grid[0][j] = BLOCK | NONE | SQUARE;
      grid[GRID_WIDTH - 1][j] = BLOCK | NONE | SQUARE;
    }

    // Add inner walls depending on current level.

    if (level == 2 || level == 4) {
      i = GRID_WIDTH / 4;
      for (j = GRID_HEIGHT / 4; j <= GRID_HEIGHT / 2 - 3; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
      j = GRID_HEIGHT / 4;
      for (i = GRID_WIDTH / 4; i <= GRID_WIDTH / 2 - 3; i++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
    }

    if (level == 3) {
      i = GRID_WIDTH / 2;
      for (j = 0; j <= 3; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
    }

    if (level == 3 || level == 5) {
      j = GRID_HEIGHT / 4;
      for (i = 5; i <= GRID_WIDTH / 4; i++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
      i = GRID_WIDTH / 4;
      for (j = GRID_HEIGHT / 4; j <= GRID_HEIGHT / 2; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
      j = GRID_HEIGHT / 2;
      for (i = 0; i <= GRID_WIDTH / 4 - 5; i++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
      }
    }

    if (level == 4) {
      i = 4;
      for (j = GRID_HEIGHT / 2 - 2; j <= GRID_HEIGHT / 2; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
      i = GRID_WIDTH / 2;
      for (j = 0; j <= 2; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
    }

    if (level == 5) {
      i = 3 * GRID_WIDTH / 8;
      for (j = 4; j <= GRID_HEIGHT / 3 - 1; j++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
      j = GRID_HEIGHT / 3 - 1;
      for (i = 3 * GRID_WIDTH / 8; i <= GRID_WIDTH / 2; i++) {
        grid[i][j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][j] = BLOCK | NONE | SQUARE;
        grid[i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
        grid[GRID_WIDTH - 1 - i][GRID_HEIGHT - 1 - j] = BLOCK | NONE | SQUARE;
      }
    }
  }

  public void initSnake() {

    int i, j;
    int m, n;

    // Create a new snake in the center of the grid and reset cell list.

    i = GRID_WIDTH  / 2;
    j = GRID_HEIGHT / 2;

    snake[4].x = i - 2; snake[4].y = j;
    snake[3].x = i - 1; snake[3].y = j;
    snake[2].x = i - 0; snake[2].y = j;
    snake[1].x = i + 1; snake[1].y = j;
    snake[0].x = i + 2; snake[0].y = j;

    headPtr = 4;
    tailPtr = 0;

    grid[i - 2][j] = SNAKE | LEFT | SNAKEHEAD;
    grid[i - 1][j] = SNAKE | LEFT | SNAKEBODY;
    grid[i][j]     = SNAKE | LEFT | SNAKEBODY;
    grid[i + 1][j] = SNAKE | LEFT | SNAKEBODY;
    grid[i + 2][j] = SNAKE | LEFT | SNAKETAIL;

    // Clear snake direction.

    direction     = NONE;
    lastDirection = NONE;

    // Relocate any mice that were overwritten.

    for (m = 0; m < NUM_MICE; m++)
      for (n = -2; n <= 2 ; n++)
        if (mouse[m].x == i + n && mouse[m].y == j)
          initMouse(m);

    // Relocate key if overwritten.

    if (keyActive)
      for (n = -2; n <= 2 ; n++)
        if (key.x == i + n && key.y == j)
          initKey();
  }

  public void moveSnake() {

    Point pt;
    int i, j;
    int k;
    int c;
    int d;

    // Lock cursor keys to prevent the current direction from being changed
    // until we are done processing it.

    lockKeys = true;

    // Move snake's head into the next cell based on current direction.

    pt = snake[headPtr];
    i = pt.x;
    j = pt.y;
    switch (direction) {
      case LEFT:
        i--;
        break;
      case RIGHT:
        i++;
        break;
      case UP:
        j--;
        break;
      case DOWN:
        j++;
        break;
      default:
        lockKeys = false;
        return;
    }

    // Unlock cursor keys and save direction.

    lockKeys = false;
    lastDirection = direction;

    // Skip if no direction given.

    if (direction == NONE)
      return;

    // Get the type of the new cell.

    c = grid[i][j] & TYPE_MASK;

    // Check if we hit a wall or ourselves.

    if (c == BLOCK || c == SNAKE) {
      if (loaded && sound)
        bonkSound.play();
      endLife();
      return;
    }

    // Replace current head with the appropriate body part.

    d = grid[pt.x][pt.y] & DIR_MASK;
    if (d == direction)
      grid[pt.x][pt.y] = SNAKE | d | SNAKEBODY;
    else if (d == LEFT && direction == UP)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB1;
    else if (d == UP && direction == RIGHT)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB1;
    else if (d == RIGHT && direction == DOWN)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB1;
    else if (d == DOWN && direction == LEFT)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB1;
    else if (d == UP && direction == LEFT)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB2;
    else if (d == LEFT && direction == DOWN)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB2;
    else if (d == DOWN && direction == RIGHT)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB2;
    else if (d == RIGHT && direction == UP)
      grid[pt.x][pt.y] = SNAKE | direction | SNAKEELB2;

    // Change the new cell to a snake's head and set it in the cell list.

    grid[i][j] = SNAKE | direction | SNAKEHEAD;
    if (++headPtr >= snake.length)
      headPtr = 0;
    snake[headPtr].x = i;
    snake[headPtr].y = j;

    // If we got a mouse, bump the score and create a new one. Otherwise,
    // move the tail.

    if (c == MOUSE) {
      score += MOUSE_POINTS;
      if (loaded && sound)
        munchSound.play();
      for (k = 0; k < NUM_MICE; k++)
        if (mouse[k].x == i && mouse[k].y == j)
          initMouse(k);
      miceEaten++;
    }
    else {
      pt = snake[tailPtr];
      grid[pt.x][pt.y] = EMPTY & NONE & SQUARE;
      if (++tailPtr >= snake.length)
        tailPtr = 0;
      pt = snake[tailPtr];
      d = grid[pt.x][pt.y] & DIR_MASK;
      grid[pt.x][pt.y] = SNAKE | d | SNAKETAIL;
    }

    // Check if we got the key. If so, end the current level.

    if (c == KEY) {
      score += LEVEL_POINTS;
      if (loaded && sound)
        advanceSound.play();
      endLevel();
    }
  }

  public void killSnake() {

    Point pt;
    int   n;

    // Remove snake from the grid.

    n = headPtr + 1;
    if (n >= snake.length)
      n = 0;
    while(tailPtr != n) {
      pt = snake[tailPtr];
      grid[pt.x][pt.y] = EMPTY | NONE | SQUARE;
      if (++tailPtr >= snake.length)
        tailPtr = 0;
    }
  }

  public void initMouse(int n) {

    int i, j;
    int d;

    // Find an empty cell.

    do {
      i = (int) (Math.random() * GRID_WIDTH);
      j = (int) (Math.random() * GRID_HEIGHT);
    } while ((grid[i][j] & TYPE_MASK) != EMPTY);

    // Get a random direction.

    d = (int) (Math.random() * 4) + 1;
    d <<= 8;

    // Save mouse position.

    mouse[n].x = i;
    mouse[n].y = j;

    // Set the cell with mouse data.

    grid[i][j] = MOUSE | d | MOUSEBODY;
  }

  public void moveMouse(int n) {

    int i, j;
    int d;
    int m;

    // Skip move at random.

    if (Math.random() > 0.25)
      return;

    // Skip move if mouse is dead.

    if (mouse[n].x == -1 || mouse[n].y == -1)
      return;

    // Toss in a random squeak.

    if (loaded && sound && Math.random() > 0.975)
      squeakSound.play();

    // Get a random direction.

    d = (int) (Math.random() * 5);
    d <<= 8;

    // Don't allow a reversal of direction.

    m = grid[mouse[n].x][mouse[n].y] & DIR_MASK;
    if ((m == LEFT  && d == RIGHT) ||
        (m == RIGHT && d == LEFT)  ||
        (m == UP    && d == DOWN)  ||
        (m == DOWN  && d == UP))
      return;

    i = mouse[n].x;
    j = mouse[n].y;
    switch (d) {
      case LEFT:
        i--;
        break;
      case RIGHT:
        i++;
        break;
      case UP:
        j--;
        break;
      case DOWN:
        j++;
        break;
      default:
        return;
    }

    // See if the new cell is empty. If not, skip move.

    if ((grid[i][j] & TYPE_MASK) != EMPTY)
      return;

    // Clear mouse from old cell and move to the new one.

    grid[mouse[n].x][mouse[n].y] = EMPTY | NONE | SQUARE;
    mouse[n].x = i;
    mouse[n].y = j;
    grid[i][j] = MOUSE | d | MOUSEBODY;
  }

  public void killMouse(int n) {

    // Clear mouse from grid and set coordinates to (-1, -1) so we know it is
    // dead.

    grid[mouse[n].x][mouse[n].y] = EMPTY | NONE | SQUARE;
    mouse[n].x = -1;
    mouse[n].y = -1;
  }

  public void initKey() {

    int i, j;

    // Find an empty cell.

    do {
      i = (int) (Math.random() * GRID_WIDTH);
      j = (int) (Math.random() * GRID_HEIGHT);
    } while ((grid[i][j] & TYPE_MASK) != EMPTY);

    // Save key position.

    key.x = i;
    key.y = j;

    // Set the cell with key data and set the flag to show it's been added.

    grid[i][j] = KEY | NONE | KEYSHAPE;
    keyActive = true;
  }

  public Polygon translate(Polygon p, int dx, int dy) {

    Polygon polygon;
    int i;

    // Returns the polygon created by translating the given shape.

    polygon = new Polygon();
    for (i = 0; i < p.npoints; i++)
      polygon.addPoint(p.xpoints[i] + dx, p.ypoints[i] + dy);

    return polygon;
  }

  public Polygon rotate(Polygon p, int d) {

    Polygon polygon;
    int i;

    // Returns the polygon created by rotating the given shape in 90 deg. increments.

    polygon = new Polygon();
    for (i = 0; i < p.npoints; i++)
      switch (d) {
        case LEFT:
          polygon.addPoint(p.ypoints[i], (GRID_SIZE - 1) - p.xpoints[i]);
          break;
        case RIGHT:
          polygon.addPoint((GRID_SIZE - 1) - p.ypoints[i], p.xpoints[i]);
          break;
        case DOWN:
          polygon.addPoint((GRID_SIZE - 1) - p.xpoints[i], (GRID_SIZE - 1) - p.ypoints[i]);
          break;
        default:
          polygon.addPoint(p.xpoints[i], p.ypoints[i]);
          break;
      }

    return polygon;
  }

  public Polygon mirror(Polygon p) {

    Polygon polygon;
    int i;

    // Returns the polygon created by mirroring the given shape.

    polygon = new Polygon();
    for (i = 0; i < p.npoints; i++)
      polygon.addPoint((GRID_SIZE - 1) - p.xpoints[i], p.ypoints[i]);

    return polygon;
  }

  public Color fade(Color s, Color e, double pct) {

    int r, g, b;

    // Fade the starting color to the ending color by the given percentage.

    if (pct < 0.0)
      return e;
    if (pct > 1.0)
      return s;

    r = e.getRed() + (int) Math.round(pct * (s.getRed() - e.getRed()));
    g = e.getGreen() + (int) Math.round(pct * (s.getGreen() - e.getGreen()));
    b = e.getBlue() + (int) Math.round(pct * (s.getBlue() - e.getBlue()));

    return(new Color(r, g, b));
  }

  public void paint(Graphics g) {

    update(g);
  }

  public void update(Graphics g) {

    Dimension d = size();
    int width, height;
    int xOff, yOff;
    int i, j;
    int m;
    int n;
    Polygon p;
    String s;

    // Create the offscreen graphics context, if no good one exists.

    if (offGraphics == null || d.width != offDimension.width || d.height != offDimension.height) {
      offDimension = d;
      offImage = createImage(d.width, d.height);
      offGraphics = offImage.getGraphics();
    }

    // Fill in applet background.

    offGraphics.setColor(bgColor);
    offGraphics.fillRect(0, 0, d.width, d.height);

    // Center game area.

    width  = GRID_WIDTH  * GRID_SIZE;
    height = GRID_HEIGHT * GRID_SIZE;
    xOff = (d.width - width) / 2;
    yOff = (d.height - (height + 2 * fontHeight)) / 2;
    offGraphics.translate(xOff, yOff);

    // Fill in playing field.

    if (gameState == LEVEL)
      offGraphics.setColor(fade(fieldColor, bgColor, (double) levelCounter / (double) LEVEL_COUNT));
    else
      offGraphics.setColor(fieldColor);
    offGraphics.fillRect(0, 0, GRID_WIDTH * GRID_SIZE, GRID_HEIGHT * GRID_SIZE);

    // Fill in each grid cell with the appropriate shape.

    for (i = 0; i < GRID_WIDTH; i++)
      for (j = 0; j < GRID_HEIGHT; j++)
        switch (grid[i][j] & TYPE_MASK) {

          case EMPTY:
            break;

          case BLOCK:
            if (gameState == LEVEL)
              offGraphics.setColor(fade(blockColor, bgColor, (double) levelCounter / (double) LEVEL_COUNT));
            else
              offGraphics.setColor(blockColor);
            offGraphics.fillRect(i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE);
            offGraphics.setColor(bgColor);
            offGraphics.drawRect(i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE);
            break;

          case SNAKE:
            n = grid[i][j] & SHAPE_MASK;
            switch (n) {
              case SNAKEHEAD:
                p = snakeHead;
                break;
              case SNAKEBODY:
                p = snakeBody;
                break;
              case SNAKEELB1:
                p = snakeElb1;
                break;
              case SNAKEELB2:
                p = snakeElb2;
                break;
              case SNAKETAIL:
                p = snakeTail;
                break;
              default:
                p = snakeHead;
                break;
            }
            p = translate(rotate(p, grid[i][j] & DIR_MASK), i * GRID_SIZE, j * GRID_SIZE);
            if (gameState == LEVEL)
              offGraphics.setColor(fade(snakeColor, bgColor, (double) levelCounter / (double) LEVEL_COUNT));
            else if (gameState == END || gameState == OVER)
              offGraphics.setColor(fade(snakeColor, fieldColor, (double) endCounter / (double) END_COUNT));
            else
              offGraphics.setColor(snakeColor);
            offGraphics.fillPolygon(p);
            offGraphics.drawPolygon(p);
            offGraphics.drawLine(p.xpoints[p.npoints - 1], p.ypoints[p.npoints - 1], p.xpoints[0], p.ypoints[0]);
            if (gameState == END || gameState == OVER)
              offGraphics.setColor(fade(bgColor, fieldColor, (double) endCounter / (double) END_COUNT));
            else
              offGraphics.setColor(bgColor);
            if (n == SNAKEHEAD || n == SNAKETAIL)
              for (m = 0; m < p.npoints - 1; m++)
                offGraphics.drawLine(p.xpoints[m], p.ypoints[m], p.xpoints[m + 1], p.ypoints[m + 1]);
            if (n == SNAKEBODY) {
              offGraphics.drawLine(p.xpoints[0], p.ypoints[0], p.xpoints[1], p.ypoints[1]);
              offGraphics.drawLine(p.xpoints[2], p.ypoints[2], p.xpoints[3], p.ypoints[3]);
            }
            if (n == SNAKEELB1 || n == SNAKEELB2) {
              offGraphics.drawLine(p.xpoints[0], p.ypoints[0], p.xpoints[1], p.ypoints[1]);
              offGraphics.drawLine(p.xpoints[1], p.ypoints[1], p.xpoints[2], p.ypoints[2]);
              offGraphics.drawLine(p.xpoints[3], p.ypoints[3], p.xpoints[4], p.ypoints[4]);
              offGraphics.drawLine(p.xpoints[4], p.ypoints[4], p.xpoints[5], p.ypoints[5]);
              offGraphics.drawLine(p.xpoints[5], p.ypoints[5], p.xpoints[6], p.ypoints[6]);
            }
            break;

          case MOUSE:
            if (gameState == LEVEL)
              offGraphics.setColor(fade(mouseColor, bgColor, (double) levelCounter / (double) LEVEL_COUNT));
            else
              offGraphics.setColor(mouseColor);
            p = translate(rotate(mouseBody, grid[i][j] & DIR_MASK), i * GRID_SIZE, j * GRID_SIZE);
            offGraphics.fillPolygon(p);
            offGraphics.setColor(bgColor);
            offGraphics.drawPolygon(p);
            offGraphics.drawLine(p.xpoints[p.npoints - 1], p.ypoints[p.npoints - 1], p.xpoints[0], p.ypoints[0]);
            break;

          case KEY:
            p = translate(rotate(keyShape, grid[i][j] & DIR_MASK), i * GRID_SIZE, j * GRID_SIZE);
            offGraphics.setColor(keyColor);
            offGraphics.fillPolygon(p);
            offGraphics.setColor(bgColor);
            offGraphics.drawPolygon(p);
            offGraphics.drawLine(p.xpoints[p.npoints - 1], p.ypoints[p.npoints - 1], p.xpoints[0], p.ypoints[0]);
            break;

          default:
            break;
        }

    // Outline playing field.

    offGraphics.setColor(fieldColor);
    offGraphics.drawRect(0, 0, GRID_WIDTH * GRID_SIZE, GRID_HEIGHT * GRID_SIZE - 1);

    // Display status and messages.

    offGraphics.setFont(font);

    offGraphics.setColor(fieldColor);
    i = height - 1;
    j = height + 3 * fontHeight / 2;
    offGraphics.drawRect(0, i, width, 2 * fontHeight);

    offGraphics.setColor(fgColor);
    s = "Score: " + score;
    offGraphics.drawString(s, fontWidth, j);
    s = "Level: " + levelTotal;
    offGraphics.drawString(s, (width - fm.stringWidth(s)) / 4, j);
    s = "Lives: " + lives;
    offGraphics.drawString(s, 3 * (width - fm.stringWidth(s)) / 4, j);
    s = "High: " + highScore;
    offGraphics.drawString(s, width - (fontWidth + fm.stringWidth(s)), j);
    if (paused) {
      s = "Paused";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, j);
    }
    else if (!sound) {
      s = "Muted";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, j);
    }

    if (gameState == INIT || gameState == OVER) {
      offGraphics.setColor(bgColor);
      s = "Snake Pit";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2 + 1, height / 3 + fontHeight + 1);
      s = "Copyright 1998 by Mike Hall";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2 + 1, height / 3 + 2 * fontHeight + 1);
      offGraphics.setColor(fgColor);
      s = "Snake Pit";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, height / 3 + fontHeight);
      s = "Copyright 1998 by Mike Hall";
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, height / 3 + 2 * fontHeight);
      offGraphics.setColor(fgColor);
      if (!loaded)
        s = "Loading sounds...";
      else
      s = "Game Over - 'S' to Start";
      offGraphics.setColor(bgColor);
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2 + 1, 2 * height / 3 + 1);
      offGraphics.setColor(fgColor);
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, 2 * height / 3);
    }
    if (gameState == LEVEL) {
      s = "Advancing to Level " + (levelTotal + 1);
      offGraphics.setColor(bgColor);
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2 + 1, height / 2 + 1);
      offGraphics.setColor(fgColor);
      offGraphics.drawString(s, (width - fm.stringWidth(s)) / 2, height / 2);
    }

    // Copy the off screen buffer to the screen.

    offGraphics.translate(-xOff, -yOff);
    g.drawImage(offImage, 0, 0, this);
  }
}


Back to the SnakePit applet page

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.

 Microsoft Visual Studio 2010 Showcase
 Avaya Developer Showcase
 MSDN Spotlight
 PHP for Windows Showcase
XML error: undefined entity at line 39
advertisement
Receive Articles via our XML/RSS feed
Receive Articles via our XML/RSS feed

JavaBytes
Internet Cyclone
This powerful, easy-to-use, internet optimizer is for Windows 95, 98, ME, NT, 2000 and XP. It's designed to automatically optimize your Windows settings, boosting your Internet connection up to 200%.

Windows 7: From Beta to Final Code in One Year
Google Shows Off Chrome OS, Releases Source
Microsoft Shows Off Silverlight 4, IE9 Plans
Metasploit Expands Vulnerability Test Framework
HyperCard Reborn?
Fedora 12 Takes Aim at Linux Networking
Top Supercomputer Nearly Doubles in Speed
Fedora 12 Linux Tackles Virtualization
Apple Gives iPhone Developers App Status Tracker
Novell Sets OpenSUSE 11.2 Free

Creating Custom Export Filters for StarOffice with XSLT
WPF Wonders: Using DataTemplates
Crystal Reports Family Offers Options for Developers
Avaya Aura Session Manager video
Avaya Aura Overview video
Exploring HTML 5's Audio/Video Multimedia Support
Overriding Virtual Functions? Use C++0x Attributes to Avoid Bugs.
Understanding the Cloud Computing Security Vulnerabilities
Cisco and IBM Target a Greener World
Upgrade to Visual Studio 2010 with the Ultimate Offer

Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map  |   Network Map  |   About

internet.commediabistro.comJusttechjobs.comGraphics.com

Search:

WebMediaBrands Corporate Info

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs