📄 pushpuzzlecanvas.java
字号:
/* * * Copyright (c) 2007, Sun Microsystems, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */package example.pushpuzzle;import javax.microedition.lcdui.*;import javax.microedition.lcdui.game.GameCanvas;import javax.microedition.lcdui.game.LayerManager;import javax.microedition.lcdui.game.Sprite;import javax.microedition.lcdui.game.TiledLayer;import javax.microedition.media.Manager;import javax.microedition.media.Player;import javax.microedition.media.control.ToneControl;import java.io.IOException;import java.io.InputStream;/** * 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 { /** Pan Rate; number of milliseconds between screen updates */ private static final int PanRate = 50; 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; /** 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 final Board board; /** The score object */ private Score score; /** The listener used to report solved events */ private CommandListener listener; /** The TextBox to input new level numbers */ private TextBox levelText; // for input of new level /** 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; /** 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 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(); } /** * 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; try { l = Integer.parseInt(s); } catch (java.lang.NumberFormatException e) { return false; } 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; 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; } /** 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; 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); } /** * 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 + -