FileDocCategorySizeDatePackage
WormPit.javaAPI DocJ2ME MIDP 2.014493Thu Nov 07 12:02:20 GMT 2002example.wormgame

WormPit

public class WormPit extends javax.microedition.lcdui.Canvas implements Runnable
The WormPit contains a Worm and some WormFood. The Worm will slither around the pit in search of WormFood. If the Worm eats it will grow in length. The Worm will be killed if it attempts to slither past the edge of the pit or if it eats itself.

Fields Summary
private WormFood
myFood
Handle to target food.
private Worm
myWorm
Handle to current worm object.
private boolean
gameOver
Flag to indicate when the game is finished.
private boolean
gamePaused
Flag to indicate if current game is paused.
private boolean
gameRestart
Flag to indicate game is restarted.
private boolean
forceRedraw
Flag to indicate forced repaint is needed.
private boolean
gameDestroyed
Flag to indicate the game is to be completely destroyed.
private int
score
Current game score.
private int
level
Current game level.
private int
foodEaten
Number of pieces of food eaten since the last level change.
private int
width
Current screen width in pixels.
private int
height
Current screen height in pixels.
private javax.microedition.media.Player
audioPlayer
Audio player for background tune.
private javax.microedition.media.Player
tonePlayer
Tone player.
static int
CellWidth
Current screen size in cells.
static int
CellHeight
Current screen height in cells.
private static final int
START_POS
Initial offset for screen rendering.
private static final int
SCORE_CHAR_HEIGHT
Font height for rendering the score message.
private static final int
SCORE_CHAR_WIDTH
Font width for rendering the score message.
private static final int
SCORE_HEIGHT
Height for two lines of score message text.
private static final int
DEFAULT_WAIT
Default delay between worm repaints. (400 milliseconds)
static final byte
MAX_LEVELS
Maximum number of difficulty levels. (10)
static final int
FOOD_COLOUR
Color for target food object. (0x00ff00)
static final int
TEXT_COLOUR
Color for text objects. (0xff0000)
static final int
ERASE_COLOUR
Color for erasing worm cells. (0xffffff)
static final int
DRAW_COLOUR
Color for drawing worm cells. (0x000000)
public static final int
CELL_SIZE
Size of a cell for worm rendering.
Constructors Summary
public WormPit()
Default constructor for worm pit. Initialized the food and worm objects.


     
	Font defaultFont  = Font.getDefaultFont();
	SCORE_CHAR_WIDTH  = defaultFont.charWidth('S");
	SCORE_CHAR_HEIGHT = defaultFont.getHeight();
	SCORE_HEIGHT      = SCORE_CHAR_HEIGHT * 2;
    
	width  = round(getWidth());
	height = round(getHeight()-SCORE_HEIGHT);
	WormPit.CellWidth  = (width-(START_POS*2)) / WormPit.CELL_SIZE;
	WormPit.CellHeight = (height-(START_POS*2)) / WormPit.CELL_SIZE;
	myWorm = new Worm(this);

	/* Generate food for worm to eat */
	myFood  = new WormFood(this);
	int x = myFood.getX();
	int y = myFood.getY();
	while (myWorm.contains(x, y)) {
	    myFood.regenerate();        // regenerate if food placed under worm
	    x = myFood.getX();  y = myFood.getY();
	}
    
Methods Summary
public voidcreateAudioPlayer()
Create an audio player.

	byte[] bkmelody = {
			ToneControl.VERSION, 1,
			ToneControl.SET_VOLUME, 40,
			76, 8,
			81, 24,
			76, 8,
			88, 24,
			81, 8,
			85, 16,
			83, 8,
			85, 8,
			81, 16,
			76, 16,
			81, 16,
			90, 16,
			88, 16,
			85, 8,
			86, 8,
			88, 48,
			ToneControl.SILENCE, 8,
			76, 8,
			81, 16,
			90, 16,
			88, 16,
			85, 8,
			86, 8,
			88, 16,
			83, 8,
			85, 8,
			81, 16,
			76, 16,
			81, 16,
			85, 8,
			86, 8,
			83, 24,
			81, 8,
			81, 32
	};

	byte[] tseq = {
			ToneControl.VERSION, 1,
			64, 4, 
			65, 4, 
			66, 4
	};

	if (audioPlayer != null) {
	    audioPlayer.close();
	    audioPlayer = null;
	    try {
		Thread.sleep(200);
	    } catch (Exception ex) { }
	}
	
	try {
	    ToneControl tControl;

	    tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
	    tonePlayer.realize();
	    tControl = (ToneControl)tonePlayer.getControl("ToneControl");
	    tControl.setSequence(tseq);

	    audioPlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
	    audioPlayer.setLoopCount(-1);
	    audioPlayer.realize();
	    tControl = (ToneControl)audioPlayer.getControl("ToneControl");
	    tControl.setSequence(bkmelody);
	    audioPlayer.start();


	} catch (Exception ex) {
	    ex.printStackTrace();
	}
    
public voiddestroyAudioPlayer()
Destroy the audio player. Call this destroy the audio player.

	synchronized (myWorm) {
	    if (audioPlayer != null) {
		audioPlayer.close();
		audioPlayer = null;
	    }
	    if (tonePlayer != null) {
		tonePlayer.close();
		tonePlayer = null;
	    }
	    myWorm.notifyAll();
	}
    
public voiddestroyGame()
Destroy the entire game. Call this prior to destroying the MIDlet.

	synchronized (myWorm) {
	    gameDestroyed = true;
	    //myWorm.notifyAll();
	    myWorm.notifyAll();
	}
    
public intgetLevel()
Get the difficulty level.

return
current game level
see
#setLevel

	return level;
    
public intgetScore()
Get the score of this game.

return
current score

	return score;
    
protected voidhideNotify()
Notification handler when canvas hidden. Forces a redraw when canvas is shown again. Signals that the game is paused while the canvas is obscured.

	super.hideNotify();
	forceRedraw = true;
	if (!gameOver) {
	    gamePaused = true;
	}
    
static booleanisInBounds(int x, int y)
Returns true if the given point is within the bounds of the worm pit.

param
x x coordinate of point to check (0 - CellWidth)
param
y y coordinate of point to check (0 - CellHeight)
return
true, if coordinate is in the worm pit

	if ((x < 0) || (x >= WormPit.CellWidth)) {
	    return false;
	}
	if ((y < 0) || (y >= WormPit.CellHeight)) {
	    return false;
	}
	return true;
    
public voidkeyPressed(int keyCode)
Handle keyboard input. This is used for worm movement.

param
keyCode pressed key is either Canvas arrow key (UP, DOWN, LEFT, RIGHT) or simulated with KEY_NUM (2, 8, 4,6).

	switch (getGameAction(keyCode)) {
	case Canvas.UP:
	    myWorm.setDirection(Worm.UP);
	    break;
	case Canvas.DOWN:
	    myWorm.setDirection(Worm.DOWN);
	    break;
	case Canvas.LEFT:
	    myWorm.setDirection(Worm.LEFT);
	    break;
	case Canvas.RIGHT:
	    myWorm.setDirection(Worm.RIGHT);
	    break;
	case 0:
	    // There is no game action.. Use keypad constants instead
	    switch (keyCode) {
	    case Canvas.KEY_NUM2:
		myWorm.setDirection(Worm.UP);
		break;
	    case Canvas.KEY_NUM8:
		myWorm.setDirection(Worm.DOWN);
		break;
	    case Canvas.KEY_NUM4:
		myWorm.setDirection(Worm.LEFT);
		break;
	    case Canvas.KEY_NUM6:
		myWorm.setDirection(Worm.RIGHT);
		break;
	    }
	    break;
	}
    
public voidpaint(javax.microedition.lcdui.Graphics g)
Paint the worm pit and its components

param
g graphics object to be rendered

	if (forceRedraw) {
	    // Redraw the entire screen
	    forceRedraw = false;

	    // Clear background
	    g.setColor(WormPit.ERASE_COLOUR);
	    g.fillRect(0, 0, getWidth(), 
		      getHeight());

	    // Draw pit border
	    g.setColor(WormPit.DRAW_COLOUR);
	    g.drawRect(1, 1, (width - START_POS), (height - START_POS));
	    
	    // Display current level
	    g.drawString("L: " + level, START_POS, height, g.TOP|g.LEFT);
	    g.drawString("" + score, 
			 (width - (SCORE_CHAR_WIDTH * 3)), 
			 height, g.TOP|g.LEFT);

	    // Display current score
	    g.drawString("S: ", 
			 (width - (SCORE_CHAR_WIDTH * 4)), 
			 height, g.TOP|g.RIGHT);
	    g.drawString("" + score, 
			 (width - (SCORE_CHAR_WIDTH * 3)), 
			 height, g.TOP|g.LEFT);

	    // Display highest score for this level
	    g.drawString("H: ", 
			 (width - (SCORE_CHAR_WIDTH * 4)), 
			 (height + SCORE_CHAR_HEIGHT), 
			 g.TOP|g.RIGHT);
	    g.drawString("" + WormScore.getHighScore(level), 
			 (width - (SCORE_CHAR_WIDTH * 3)), 
			 (height + SCORE_CHAR_HEIGHT), 
			 g.TOP|g.LEFT);

	    // Draw worm & food
	    g.translate(START_POS, START_POS);
	    g.setClip(0, 0, CellWidth*CELL_SIZE, CellHeight*CELL_SIZE);
	    myWorm.paint(g);
	    myFood.paint(g);
	} else {
	    // Draw worm & food
	    g.translate(START_POS, START_POS);
	}

	if (gamePaused) {
	    Font pauseFont = g.getFont();
	    int fontH = pauseFont.getHeight();
	    int fontW = pauseFont.stringWidth("Paused");
	    g.setColor(WormPit.ERASE_COLOUR);
	    g.fillRect((width-fontW)/2 - 1, (height-fontH)/2,
		       fontW + 2, fontH);
	    g.setColor(WormPit.TEXT_COLOUR);
	    g.setFont(pauseFont);
	    g.drawString("Paused", (width-fontW)/2, (height-fontH)/2,
			 g.TOP|g.LEFT);
	} else if (gameOver) {
	    Font overFont = g.getFont();
	    int fontH = overFont.getHeight();
	    int fontW = overFont.stringWidth("Game Over");
	    g.setColor(WormPit.ERASE_COLOUR);
	    g.fillRect((width-fontW)/2 - 1, (height-fontH)/2,
		       fontW + 2, fontH);
	    g.setColor(WormPit.TEXT_COLOUR);
	    g.setFont(overFont);
	    g.drawString("Game Over", (width-fontW)/2, (height-fontH)/2,
			 g.TOP|g.LEFT);
	} else {
	    paintPitContents(g);
	}
	g.translate(-START_POS, -START_POS);
    
private voidpaintPitContents(javax.microedition.lcdui.Graphics g)
Paint anything currently in the pit. Overrides Canvas.paint.

param
g graphics object to be rendered

	try {
	    myWorm.update(g);    // update worm position
	    if (myFood.isAt(myWorm.getX(), myWorm.getY())) {
		myWorm.eat();
		score += level;

		foodEaten++;

		if (foodEaten > (level << 1)) {
		    /* Increase difficulty level */
		    forceRedraw = true;
		    foodEaten = 0;
		    level++;

		    if (tonePlayer != null) {
			try {
			    tonePlayer.setMediaTime(0);
			    tonePlayer.start();
			} catch (MediaException me) { }
		    }
		} else {
		    if (audioPlayer != null) {
			try {
			    Manager.playTone(69, 50, 100);   // Play audio
			} catch (MediaException me) { }
		    }
		}

		g.setColor(WormPit.ERASE_COLOUR);
		g.fillRect((width - (SCORE_CHAR_WIDTH * 3))-START_POS,
			   height-START_POS,
			   (SCORE_CHAR_WIDTH * 3),
			   SCORE_CHAR_HEIGHT);
		g.setColor(WormPit.DRAW_COLOUR);
		
		// Display new score
		g.drawString("" + score, 
			     width - (SCORE_CHAR_WIDTH * 3) - START_POS, 
			     height - START_POS, g.TOP|g.LEFT);
		
		myFood.regenerate();
		int x = myFood.getX();
		int y = myFood.getY();
		while (myWorm.contains(x, y)) {
		// generate again if food placed under worm..
		    myFood.regenerate();
		    x = myFood.getX();  y = myFood.getY();
		}
	    }
	    
	    myFood.paint(g);
	} catch (WormException se) {
	    gameOver = true;
	}
    
voidrestart()
Restart the game.

	    if (gamePaused) {
		gamePaused = false;
	    } else {
		myWorm.regenerate();
		myFood.regenerate();
		foodEaten = 0;
		score = 0;
		gameOver = false;
		if ((audioPlayer != null) && 
		    (audioPlayer.getState() == Player.PREFETCHED)) {
		    try {
			audioPlayer.setMediaTime(0);
			audioPlayer.start();
		    } catch (MediaException me) { }
		}
	    }
	    forceRedraw = true;

	    synchronized (myWorm) {
		myWorm.notifyAll();
	    }
    
private intround(int val)
Round the given value to next lowest number divisible by the cell size.

param
val number to be rounded down
return
rounded down value

	int delta = (val-(START_POS*2)) % CELL_SIZE;
	return (val - delta);
    
public voidrun()
The main execution loop.

	while (!gameDestroyed) {
	    try {
		synchronized (myWorm) {
		    if (gameOver) {
			if (WormScore.getHighScore(level) < score) {
			    /* Display score screen */
			    WormScore.setHighScore(level, score, "me");
			}
			if ((audioPlayer != null) && 
			    (audioPlayer.getState() == Player.STARTED)) {
			    try {
				audioPlayer.stop();
				Manager.playTone(60, 400, 100);
			    } catch (Exception ex) { }
			}
			repaint();
			// serviceRepaints(); // Draw immediately
			myWorm.wait();    // Wait until user presses 'restart'
		    } else if (gamePaused) {
			repaint();
			// serviceRepaints(); // Draw immediately
			myWorm.wait();    // Wait until user presses 'restart'
		    } else {
			myWorm.moveOnUpdate();
			repaint();
			// serviceRepaints(); // Draw immediately
			myWorm.wait(DEFAULT_WAIT-(level*40));
		    }
		}
	    } catch (java.lang.InterruptedException ie) {
	    }
	}
    
public voidsetLevel(int level)
Set the difficulty level. If the new level is different from the current level, any game currently in progress is terminated and the score is lost.

param
level value of new level requested
see
#getLevel

	if (this.level != level) {
	    this.level = level;
	    gameOver = true;
	    gamePaused = false;
	    foodEaten = 0;
	    score = 0;
	}