📄 pushpuzzlecanvas.java
字号:
/*
* @(#)PushPuzzleCanvas.java 1.2 03/01/22
*
* Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms
*/
package example.pushpuzzle2;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.media.*;
import javax.microedition.media.control.ToneControl;
import java.io.InputStream;
import java.io.IOException;
/**
* PushPuzzleCanvas displays the game board and handles key events.
* The PushPuzzle game logic and algorithms are separated into Board.java.
* PushPuzzleCanvas does not setup or use any Commands. Commands for each
* screen and listeners should be setup outside this class.
* PushPuzzleCanvas generates a SELECT_COMMAND when the current level
* is solved. Sequencing through screens is done in the PushPuzzle MIDlet.
* <p>
* PushPuzzleCanvas handles the reading, initialization, and sequencing
* of individual puzzle screens.
* <p>
* PushPuzzleCanvas uses the Score class to restore and save game levels
* and scores for each level. To display the scores use getScoreScreen.
* It will be initialized with the current scores.
* To select a new level use the getLevelScreen and gotoLevel
* methods.
* <p>
* PushPuzzleCanvas handled key events for LEFT, RIGHT, UP, and DOWN to
* move the pusher in the game board. Pointer pressed events
* are used to move the pusher to the target location (if possible).
* <p>
*/
class PushPuzzleCanvas extends GameCanvas implements Runnable {
/** The current level */
private int level = 1;
/** The current theme index */
private int theme;
/** True if the level has been solved */
private boolean solved;
/** number of pixels per cell (updated by readscreen) */
private int cell = 1;
/** The width of the canvas */
private int width;
/** The height of the canvas */
private int height;
/** The width of the board */
private int bwidth;
/** The height of the board */
private int bheight;
/** The board containing the location of each packet, ground, walls, etc */
private Board board;
/** The score object */
private Score score;
/** The main MIDlet */
private PushPuzzle pushpuzzle;
/** The Display of this MIDlet */
private Display display;
/** The listener used to report solved events */
private CommandListener listener;
/** The form for score display */
private Form scoreForm; // form for scores
/** The TextBox to input new level numbers */
private TextBox levelText; // for input of new level
/** Background color */
private static int groundColor = 0xff8080;
/** The index in the image of the Ground */
public final int TILE_GROUND = 1;
/** The index in the image of the Packet */
public final int TILE_PACKET = 2;
/** The index in the image of the Store */
public final int TILE_STORE = 3;
/** The index in the image of the Wall */
public final int TILE_WALL = 4;
/** The index in the image of the Pusher */
public final int TILE_PUSHER = 5;
/** Background image */
private Image themeImage;
/** Tiles forming the background */
private TiledLayer tiles;
/** The Sprite that is the pusher */
private Sprite sprite;
/** Layer manager */
private LayerManager layers;
/** Thread used for key handling and animation */
private Thread thread;
/** The target cell for runTo */
private int targetx;
/** The target cell for runTo */
private int targety;
/** Pan Rate; number of milliseconds between screen updates */
private static final int PanRate = 50;
/** The Tone player */
private Player tonePlayer;
/** The ToneController */
private ToneControl toneControl;
/** Tune to play when puzzle level is solved. */
private byte[] solvedTune = {
ToneControl.VERSION, 1,
74, 8, // 1/8 note
75, 8,
73, 8
};
/** Tune to play when a packet enters a store */
private byte[] storedTune = {
ToneControl.VERSION, 1,
50, 8, // 1/8 note
60, 8,
70, 8
};
/**
* Construct a new canvas
* @param pushpuzzle the main MIDlet
* @param s the score object
*/
public PushPuzzleCanvas(PushPuzzle pushpuzzle, Score s) {
super(false); // Don't suppress key events
this.pushpuzzle = pushpuzzle;
display = Display.getDisplay(pushpuzzle);
score = s;
board = new Board();
layers = new LayerManager();
setupTheme();
targetx = targety = -1;
height = getHeight();
width = getWidth();
}
/**
* Read the previous level number from the score file.
* Read in the level data.
*/
public void init() {
// 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);
}
}
/**
* Cleanup and destroy.
*/
public void destroy() {
hideNotify();
}
/**
* Figure out which set of icons to use based on the colors
*/
private void initColors() {
boolean isColor = display.isColor();
int numColors = display.numColors();
if (isColor) {
} else {
if (numColors > 2) {
} else {
}
}
}
/**
* Change themes.
* Cycle to the next index and try it
*/
public void changeTheme() {
theme++;
setupTheme();
score.setLevel(level, theme); // save the level and theme
setupTiles();
updateSprite(0);
}
/**
* 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.
*/
public void undoMove() {
int pos = board.getPusherLocation();
int dir = board.undoMove();
if (dir >= 0) {
updateTilesNear(pos, dir);
updateSprite(dir);
}
solved = board.solved();
}
/**
* Restart the current level.
*/
public void restartLevel() {
readScreen(level);
solved = false;
}
/**
* Start the next level.
* @param offset of the next level
* @return true if the new level was loaded
*/
public boolean nextLevel(int offset) {
updateScores(); // save best scores
if (level + offset >= 0 && readScreen(level+offset)) {
level += offset;
score.setLevel(level, theme);
solved = false;
return true;
}
return false;
}
/**
* Get the current level.
* @return the current level.
*/
public int getLevel() {
return level;
}
/**
* Get a screen to let the user change the level.
* A simple numeric TextBox will do.
* @return the textbox used to change the level number
*/
public Screen getLevelScreen() {
if (levelText == null) {
levelText = new TextBox("Enter Level",
Integer.toString(level), // default
4, TextField.NUMERIC);
} else {
levelText.setString(Integer.toString(level));
}
return levelText;
}
/**
* Go to the chosen Level.
* @return true if the new level was loaded.
*/
public boolean gotoLevel() {
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;
}
/**
* Read and setup the next level.
* Opens the resource file with the name "/Screen.<lev>"
* and tells the board to read from the stream.
* <STRONG>Must be called only with the board locked.</STRONG>
* @param lev the level number to read.
* @return true if the reading of the level worked, false otherwise.
*/
private boolean readScreen(int lev) {
if (lev <= 0) {
board.screen0(); // Initialize the default zero screen.
} else {
InputStream is = null;
try {
is = getClass().getResourceAsStream(
"/example/pushpuzzle2/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;
}
/**
* Create the Tiled layer to represent the current board.
*/
private void setupTiles() {
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);
}
/**
* Update the tile at the location.
* @param x the offset of the tile to update
* @param y the offset of the tile to update
*/
private void updateTile(int x, int y) {
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);
}
private static final int GroundColor0 = 0xffffff;
private static final int PacketColor0 = 0xff6d00;
private static final int StoreColor0 = 0xb60055;
private static final int WallColor0 = 0x006D55;
private static final int PusherColor0 = 0x6d6dff;
/**
* Setup Theme-0 generated to match screen
* size and board size.
*/
private void setupTheme0() {
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -