Fields Summary |
---|
private int | levelThe current level |
private int | themeThe current theme index |
private boolean | solvedTrue if the level has been solved |
private int | cellnumber of pixels per cell (updated by readscreen) |
private int | widthThe width of the canvas |
private int | heightThe height of the canvas |
private int | bwidthThe width of the board |
private int | bheightThe height of the board |
private Board | boardThe board containing the location of each packet, ground, walls, etc |
private Score | scoreThe score object |
private PushPuzzle | pushpuzzleThe main MIDlet |
private Display | displayThe Display of this MIDlet |
private CommandListener | listenerThe listener used to report solved events |
private Form | scoreFormThe form for score display |
private TextBox | levelTextThe TextBox to input new level numbers |
private static int | groundColorBackground color |
public final int | TILE_GROUNDThe index in the image of the Ground |
public final int | TILE_PACKETThe index in the image of the Packet |
public final int | TILE_STOREThe index in the image of the Store |
public final int | TILE_WALLThe index in the image of the Wall |
public final int | TILE_PUSHERThe index in the image of the Pusher |
private Image | themeImageBackground image |
private TiledLayer | tilesTiles forming the background |
private Sprite | spriteThe Sprite that is the pusher |
private LayerManager | layersLayer manager |
private Thread | threadThread used for key handling and animation |
private int | targetxThe target cell for runTo |
private int | targetyThe target cell for runTo |
private static final int | PanRatePan Rate; number of milliseconds between screen updates |
private Player | tonePlayerThe Tone player |
private javax.microedition.media.control.ToneControl | toneControlThe ToneController |
private byte[] | solvedTuneTune to play when puzzle level is solved. |
private byte[] | storedTuneTune to play when a packet enters a store |
private static final int | GroundColor0 |
private static final int | PacketColor0 |
private static final int | StoreColor0 |
private static final int | WallColor0 |
private static final int | PusherColor0 |
Methods Summary |
---|
private void | cancelTo()Cancel the animation.
targetx = -1;
targety = -1;
|
public void | changeTheme()Change themes.
Cycle to the next index and try it
theme++;
setupTheme();
score.setLevel(level, theme); // save the level and theme
setupTiles();
updateSprite(0);
|
void | closePlayer()
if ( tonePlayer != null ) {
toneControl = null;
tonePlayer.close();
tonePlayer = null;
}
|
public void | destroy()Cleanup and destroy.
hideNotify();
|
public int | getLevel()Get the current level.
return level;
|
public Screen | getLevelScreen()Get a screen to let the user change the level.
A simple numeric TextBox will do.
if (levelText == null) {
levelText = new TextBox("Enter Level",
Integer.toString(level), // default
4, TextField.NUMERIC);
} else {
levelText.setString(Integer.toString(level));
}
return levelText;
|
public Screen | getScoreScreen()Return the Screen to display scores.
It returns a screen with the current scores.
Form scoreForm = null; // Temp until form can do setItem
int currPushes = board.getPushes();
int bestPushes = score.getPushes();
int currMoves = board.getMoves();
int bestMoves = score.getMoves();
boolean newbest = solved &&
(bestPushes == 0 || currPushes < bestPushes);
scoreForm = new Form(null);
scoreForm.append(new StringItem(
newbest ? "New Best:\n" : "Current:\n",
currPushes + " pushes\n" +
currMoves + " moves"));
scoreForm.append(new StringItem(
newbest ? "Old Best:\n" : "Best:\n",
bestPushes + " pushes\n" +
bestMoves + " moves"));
String title = "Scores";
if (newbest) {
title = "Congratulations";
}
scoreForm.setTitle(title);
return scoreForm;
|
public boolean | gotoLevel()Go to the chosen Level.
if (levelText != null) {
String s = levelText.getString();
int l = Integer.parseInt(s);
updateScores();
if (l >= 0 && readScreen(l)) {
level = l;
score.setLevel(level, theme);
solved = false;
return true;
}
}
return false;
|
protected void | hideNotify()The canvas is being removed from the screen.
Stop the event handling and animation thread.
thread = null;
|
public void | init()Read the previous level number from the score file.
Read in the level data.
// Read the last level; if it can't be found, revert to level 0
theme = score.getTheme();
setupTheme();
level = score.getLevel();
if (!readScreen(level)) {
level = 0;
readScreen(level);
}
|
private void | initColors()Figure out which set of icons to use based on the colors
boolean isColor = display.isColor();
int numColors = display.numColors();
if (isColor) {
} else {
if (numColors > 2) {
} else {
}
}
|
protected void | keyPressed(int keyCode)Handle a single key event.
The LEFT, RIGHT, UP, and DOWN keys are used to
move the pusher within the Board.
Other keys are ignored and have no effect.
Repaint the screen on every action key.
boolean newlySolved = false;
// Protect the data from changing during painting.
synchronized (board) {
cancelTo();
int action = getGameAction(keyCode);
int move = 0;
switch (action) {
case Canvas.LEFT:
move = Board.LEFT;
break;
case Canvas.RIGHT:
move = Board.RIGHT;
break;
case Canvas.DOWN:
move = Board.DOWN;
break;
case Canvas.UP:
move = Board.UP;
break;
// case 0: // Ignore keycode that don't map to actions.
default:
return;
}
// Tell the board to move the piece
int stored = board.getStored();
int dir = board.move(move);
if (stored < board.getStored()) {
// Play a note if a packet hit the spot.
play(storedTune);
}
int pos = board.getPusherLocation();
updateTilesNear(pos, dir);
updateSprite(dir);
} // End of synchronization on the Board.
|
protected void | keyRepeated(int keyCode)Handle a repeated arrow keys as though it were another press.
int action = getGameAction(keyCode);
switch (action) {
case Canvas.LEFT:
case Canvas.RIGHT:
case Canvas.UP:
case Canvas.DOWN:
keyPressed(keyCode);
break;
default:
break;
}
|
public boolean | nextLevel(int offset)Start the next level.
updateScores(); // save best scores
if (level + offset >= 0 && readScreen(level+offset)) {
level += offset;
score.setLevel(level, theme);
solved = false;
return true;
}
return false;
|
public void | paint(Graphics g)Paint the contents of the Canvas.
The clip rectangle of the canvas is retrieved and used
to determine which cells of the board should be repainted.
flushGraphics();
|
void | play(byte[] tune)Play the simple tune supplied.
try {
if (tonePlayer == null) {
// First time open the tonePlayer
tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
tonePlayer.realize();
toneControl = (ToneControl)tonePlayer.getControl("javax.microedition.media.control.ToneControl");
}
tonePlayer.deallocate();
toneControl.setSequence(tune);
tonePlayer.start();
} catch (Exception ex){
ex.printStackTrace();
}
|
protected void | pointerPressed(int x, int y)Called when the pointer is pressed.
Record the target for the pusher.
targetx = (x - tiles.getX()) / cell;
targety = (y - tiles.getY()) / cell;
|
private boolean | readScreen(int lev)Read and setup the next level.
Opens the resource file with the name "/Screen."
and tells the board to read from the stream.
Must be called only with the board locked.
if (lev <= 0) {
board.screen0(); // Initialize the default zero screen.
} else {
InputStream is = null;
try {
is = getClass().getResourceAsStream(
"/example/pushpuzzle/data/screen."
+ lev);
if (is != null) {
board.read(is, lev);
is.close();
} else {
System.out.println(
"Could not find the game board for level "
+ lev);
return false;
}
} catch (java.io.IOException ex) {
return false;
}
}
bwidth = board.getWidth();
bheight = board.getHeight();
setupTiles();
updateSprite(0);
return true;
|
public void | restartLevel()Restart the current level.
readScreen(level);
solved = false;
|
public void | run()The main event processor. Events are polled and
actions taken based on the directional events.
Graphics g = getGraphics(); // Of the buffered screen image
Thread mythread = Thread.currentThread();
// Loop handling events
while (mythread == thread) {
try { // Start of exception handler
boolean newlySolved = false;
if (!solved && board.solved()) {
newlySolved = solved = true;
play(solvedTune);
}
if (newlySolved && listener != null) {
listener.commandAction(List.SELECT_COMMAND, this);
}
if (targetx >= 0 && targety >= 0) {
int dir = board.runTo(targetx, targety, 1);
int pos = board.getPusherLocation();
if (dir < 0) {
targetx = targety = -1; // Cancel target
} else {
updateTilesNear(pos, dir);
updateSprite(dir);
}
}
// Check that the pusher is not to close to the edge
int loc = board.getPusherLocation();
int x = (loc & 0x7fff) * cell;
int y = ((loc >> 16) & 0x7fff) * cell;
int lx = tiles.getX();
int ly = tiles.getY();
int panScale = cell / 4;
if (panScale < 1)
panScale = 1;
// If the sprite is too near the edge (or off) pan
if (lx + x > width - cell - cell ) {
tiles.move(-panScale, 0);
sprite.move(-panScale, 0);
}
if (lx + x < cell) {
tiles.move(panScale, 0);
sprite.move(panScale, 0);
}
if (ly + y > height - cell - cell) {
tiles.move(0, -panScale);
sprite.move(0, -panScale);
}
if (ly + y < cell) {
tiles.move(0, panScale);
sprite.move(0, panScale);
}
// Draw all the layers and flush
layers.paint(g, 0, 0);
if (mythread == thread) {
flushGraphics();
}
// g.drawString("PushPuzzle Level " + level, 0, height,
// Graphics.BOTTOM|Graphics.LEFT);
try {
mythread.sleep(PanRate);
} catch (java.lang.InterruptedException e) {
// Ignore
}
} catch (Exception e) {
e.printStackTrace();
}
}
|
public void | setCommandListener(CommandListener l)Add a listener to notify when the level is solved.
The listener is send a List.SELECT_COMMAND when the
level is solved.
super.setCommandListener(l);
listener = l;
|
private void | setupTheme()Setup the theme by reading the images and setting up
the sprite and picking the tile size.
Uses the current theme index.
If the image with the current index can't be found
retry with theme = 0.
if (sprite != null) {
layers.remove(sprite);
sprite = null;
}
if (theme > 0) {
try {
StringBuffer name =
new StringBuffer("/example/pushpuzzle/images/Theme-");
name.append(theme);
name.append(".png");
themeImage = Image.createImage(name.toString());
// Cells are square using the minimum of the width and height
int h = themeImage.getHeight();
int w = themeImage.getWidth();
cell = (w < h) ? w : h;
} catch (IOException e) {
theme = 0;
setupTheme0();
}
} else {
setupTheme0();
}
sprite = new Sprite(themeImage, cell, cell);
sprite.defineReferencePixel(cell/2, cell/2);
int seq[] = new int[] {TILE_PUSHER-1};
sprite.setFrameSequence(seq);
layers.insert(sprite, 0);
|
private void | setupTheme0()Setup Theme-0 generated to match screen
size and board size.
int bwidth = board.getWidth();
int bheight = board.getHeight();
int w = getWidth();
int h = getHeight(); // height of Canvas
cell = ((h-14) / bheight < w / bwidth) ? (h-14) / bheight : w / bwidth;
// Create a mutable image and initialize
themeImage = Image.createImage(cell * 5, cell);
Graphics g = themeImage.getGraphics();
g.setColor(GroundColor0);
g.fillRect((TILE_GROUND - 1 ) * cell, 0, cell*TILE_PUSHER, cell);
g.setColor(PacketColor0);
g.fillRect((TILE_PACKET- 1 ) * cell + 1, 1, cell - 2, cell - 2);
g.setColor(StoreColor0);
g.drawRect((TILE_STORE- 1 ) * cell + 1, 1, cell - 2, cell - 2);
g.setColor(WallColor0);
g.fillRect((TILE_WALL- 1 ) * cell, 0, cell, cell);
g.setColor(PusherColor0);
g.fillArc((TILE_PUSHER- 1 ) * cell, 0, cell, cell, 0, 360);
|
private void | setupTiles()Create the Tiled layer to represent the current board.
if (tiles != null) {
layers.remove(tiles);
}
// Figure out how many cells are needed to cover canvas.
int w = (width + cell - 1) / cell;
int h = (height + cell - 1) / cell;
tiles = new TiledLayer(w > bwidth ? w : bwidth,
h > bheight ? h : bheight,
themeImage, cell, cell);
/** Fill it all with background */
tiles.fillCells(0, 0, w, h, TILE_GROUND);
// Initialize the background tileset
for (int y = 0; y < bheight; y++) {
for (int x = 0; x < bwidth; x++) {
updateTile(x, y);
}
}
layers.append(tiles);
|
protected void | showNotify()The canvas is being displayed.
Stop the event handling and animation thread.
thread = new Thread(this);
thread.start();
|
public void | undoMove()Undo the last move if possible. Redraw the cell
the pusher occupies after the undone move and the cells
in the direction of the original move.
Here so undo can be triggered by a command.
int pos = board.getPusherLocation();
int dir = board.undoMove();
if (dir >= 0) {
updateTilesNear(pos, dir);
updateSprite(dir);
}
solved = board.solved();
|
private void | updateScores()Update the scores for the current level if it has
been solved and the scores are better than before.
if (!solved)
return;
int sp = score.getPushes();
int bp = board.getPushes();
int bm = board.getMoves();
/*
* Update the scores. If the score for this level is lower
* than the last recorded score save the lower scores.
*/
if (sp == 0 || bp < sp) {
score.setLevelScore(bp, bm);
}
|
private void | updateSprite(int dir)Update the Sprite location from the board supplied position
int loc = board.getPusherLocation();
int x = (loc & 0x7fff) * cell;
int y = ((loc >> 16) & 0x7fff) * cell;
// Update sprite location
sprite.setPosition(tiles.getX() + x, tiles.getY() + y);
dir = Board.RIGHT; // BUG: Graphics.drawRegion doesn't do xofrm
switch (dir & 0x03) {
case Board.LEFT:
sprite.setTransform(Sprite.TRANS_ROT180);
break;
case Board.UP:
sprite.setTransform(Sprite.TRANS_ROT90);
break;
case Board.DOWN:
sprite.setTransform(Sprite.TRANS_ROT270);
break;
default:
sprite.setTransform(Sprite.TRANS_NONE);
break;
}
|
private void | updateTile(int x, int y)Update the tile at the location.
int tile = 0;
byte v = board.get(x, y);
switch (v & ~Board.PUSHER) {
case Board.WALL:
tile = TILE_WALL;
break;
case Board.PACKET:
case Board.PACKET | Board.STORE:
tile = TILE_PACKET;
break;
case Board.STORE:
tile = TILE_STORE;
break;
case Board.GROUND:
default:
tile = TILE_GROUND;
}
tiles.setCell(x, y, tile);
|
void | updateTilesNear(int loc, int dir)Queue a repaint for an area around the specified location.
int x = loc & 0x7fff;
int y = (loc >> 16) & 0x7fff;
// Update cells if any were moved
if (dir >= 0 && ((dir & Board.MOVEPACKET) != 0)) {
updateTile(x, y);
updateTile(x+1, y);
updateTile(x-1, y);
updateTile(x, y+1);
updateTile(x, y-1);
}
|