As with previous Forum Nokia MIDlet examples, the MIDlet is used as a state machine that manages the various screens and transitions between them.
This class cooperates with class SplashScreen
(through
methods splashScreenPainted
and splashScreenDone
)
to perform background initialization in method init
while
the splash screen is being displayed.
The methods readRecordStore
and writeRecordStore
are
used to keep the high score in a record store named "BESTTIME".
Create the SheepDogMIDlet
class
file.
Import the required classes.
// unnamed package import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.rms.*; import java.util.*; import java.io.*;
Set SheepdogMIDlet
to
extend MIDlet
and to implement Runnable
.
Make sure it includes the creation of a SheepdogCanvas
object.
public class SheepdogMIDlet extends MIDlet implements Runnable { private static final String RS_NAME = "BESTTIME"; private MenuList menuList; private SheepdogCanvas sheepdogCanvas; private boolean initDone = false; private static final Random random = new Random(); private boolean hasBestTime = false; private long bestTime; public SheepdogMIDlet() { }
Construct
the startApp
, pauseApp
and destroyApp
methods,
required for a MIDlet to run.
public void startApp() { Displayable current = Display.getDisplay(this).getCurrent(); if (current == null) { // first time we've been called Display.getDisplay(this).setCurrent(new SplashScreen(this)); } else { if (current == sheepdogCanvas) { sheepdogCanvas.start(); // start its animation thread } Display.getDisplay(this).setCurrent(current); } } public void pauseApp() { Displayable current = Display.getDisplay(this).getCurrent(); if (current == sheepdogCanvas) { sheepdogCanvas.stop(); // kill its animation thread } } public void destroyApp(boolean unconditional) { if (sheepdogCanvas != null) { sheepdogCanvas.stop(); // kill its animation thread } }
Create the various methods used to control the Midlet.
private void quit() { destroyApp(false); notifyDestroyed(); } public void run() { init(); } private synchronized void init() { if (!initDone) { readRecordStore(); SoundEffects.getInstance(); menuList = new MenuList(this); sheepdogCanvas = new SheepdogCanvas(this); initDone = true; } } void splashScreenPainted() { new Thread(this).start(); // start background initialization } void splashScreenDone() { init(); // if not already done Display.getDisplay(this).setCurrent(menuList); } void menuListContinue() { Display.getDisplay(this).setCurrent(sheepdogCanvas); sheepdogCanvas.start(); } void menuListNewGame() { sheepdogCanvas.init(); Display.getDisplay(this).setCurrent(sheepdogCanvas); sheepdogCanvas.start(); } void menuListInstructions() { // create and discard a new Instructions screen each time, to // avoid keeping heap memory for it when it's not in use Display.getDisplay(this).setCurrent(new InstructionsScreen(this)); } void menuListHighScore() { // create and discard a new High Score screen each time, to // avoid keeping heap memory for it when it's not in use Display.getDisplay(this).setCurrent(new HighScoreScreen(this)); } void menuListQuit() { quit(); } void sheepdogCanvasMenu() { sheepdogCanvas.stop(); menuList.setGameActive(true); Display.getDisplay(this).setCurrent(menuList); } void sheepdogCanvasGameOver(long time) { sheepdogCanvas.stop(); menuList.setGameActive(false); Display.getDisplay(this).setCurrent(new GameOverScreen(this, time)); } void gameOverDone() { Display.getDisplay(this).setCurrent(menuList); } void instructionsBack() { Display.getDisplay(this).setCurrent(menuList); } void highScoreBack() { Display.getDisplay(this).setCurrent(menuList); } // method needed by lots of classes, shared by putting it here static Image createImage(String filename) { Image image = null; try { image = Image.createImage(filename); } catch (java.io.IOException ex) { // just let return value be null } return image; } // method needed by lots of classes, shared by putting it here static int random(int size) { return (random.nextInt() & 0x7FFFFFFF) % size; } // only the MIDlet has access to the display, so put this method here void flashBacklight(int millis) { Display.getDisplay(this).flashBacklight(millis); } // only the MIDlet has access to the display, so put this method here void vibrate(int millis) { Display.getDisplay(this).vibrate(millis); }
Create the methods needed for high score keeping and recording.
long getBestTime() { return hasBestTime ? bestTime : -1; } boolean checkBestTime(long time) { if (!hasBestTime || (time < bestTime)) { hasBestTime = true; bestTime = time; writeRecordStore(); return true; } else { return false; } private void readRecordStore() { hasBestTime = false; RecordStore rs = null; ByteArrayInputStream bais = null; DataInputStream dis = null; try { rs = RecordStore.openRecordStore(RS_NAME, false); byte[] data = rs.getRecord(1); bais = new ByteArrayInputStream(data); dis = new DataInputStream(bais); bestTime = dis.readLong(); hasBestTime = true; } catch (IOException ex) { // hasBestTime will still be false } catch (RecordStoreException ex) { // hasBestTime will still be false } finally { if (dis != null) { try { dis.close(); } catch (IOException ex) { // no error handling necessary here } } if (bais != null) { try { bais.close(); } catch (IOException ex) { // no error handling necessary here } } if (rs != null) { try { rs.closeRecordStore(); } catch (RecordStoreException ex) { // no error handling necessary here } } } }
Create the method for writing a new high score.
// this will only be called when we have a best time private void writeRecordStore() { RecordStore rs = null; ByteArrayOutputStream baos = null; DataOutputStream dos = null; try { rs = RecordStore.openRecordStore(RS_NAME, true); baos = new ByteArrayOutputStream(); dos = new DataOutputStream(baos); dos.writeLong(bestTime); byte[] data = baos.toByteArray(); if (rs.getNumRecords() == 0) { // new record store rs.addRecord(data, 0, data.length); } else { // existing record store: will have one record, id 1 rs.setRecord(1, data, 0, data.length); } } catch (IOException ex) { // just leave the best time unrecorded } catch (RecordStoreException ex) { // just leave the best time unrecorded } finally { if (dos != null) { try { dos.close(); } catch (IOException ex) { // no error handling necessary here } } if (baos != null) { try { baos.close(); } catch (IOException ex) { // no error handling necessary here } } if (rs != null) { try { rs.closeRecordStore(); } catch (RecordStoreException ex) { // no error handling necessary here } } } } }