The MIDlet contains three classes needed to manage the game logic and create the game screen:
The GameStatusListener
is an interface that defines
one method: gameOver(int)
. The integer it takes as
a parameter represents the reason why the game ended. The interface
also defines these reasons.
public interface GameStatusListener { public static int PLAYER_DIED = 0; public static int GAME_COMPLETED = 1; public void gameOver(int reason); }
To implement the GameCanvasView
class, which
draws the game elements on the screen:
Use the checkKeys
method to determine whether the user has pressed
any of the game keys. The method also updates the game state.
/** * Check game keys for controlling movement and firing */ private void checkKeys() { if (!pointerDragged && (!gameOverWellDone || !gameOverBadLuck)) { boolean leftPressed = false; boolean rightPressed = false; boolean upPressed = false; boolean downPressed = false; int keyState = getKeyStates(); if ((keyState & FIRE_PRESSED) != 0) { fire(); } if ((keyState & GameCanvas.LEFT_PRESSED) != 0) { leftPressed = true; } if ((keyState & GameCanvas.RIGHT_PRESSED) != 0) { rightPressed = true; } if ((keyState & GameCanvas.UP_PRESSED) != 0) { upPressed = true; } if ((keyState & GameCanvas.DOWN_PRESSED) != 0) { downPressed = true; } game3DManager.setKeysPressed(leftPressed, rightPressed, upPressed, downPressed); } }
Use the pointerPressed
and pointerDragged
methods to also allow the user to control movement and firing by
touch on touch devices.
/** * Handle pressed events * @param x * @param y */ protected void pointerPressed(int x, int y) { if (!paused) { firingTimer.schedule(new TimerTask() { public void run() { if (!pointerDragged) { fire(); } } }, 100); } startX = x; startY = y; playKey.pointerPressed(x, y); pauseKey.pointerPressed(x, y); newGameKey.pointerPressed(x, y); exitKey.pointerPressed(x, y); render(); } // ... /** * Handle dragged events * @param x * @param y */ protected void pointerDragged(int x, int y) { pointerDragged = true; if (!paused) { int dX = startX - x; int dY = startY - y; boolean leftPressed = false; boolean rightPressed = false; boolean upPressed = false; boolean downPressed = false; // Control movement by dragging if (Math.abs(dX) > Math.abs(dY)) { if (dX > DRAG_THRESHOLD) { leftPressed = true; } else if (dX < -DRAG_THRESHOLD) { rightPressed = true; } } else { if (dY > DRAG_THRESHOLD) { upPressed = true; } else if (dY < -DRAG_THRESHOLD) { downPressed = true; } } game3DManager.setKeysPressed(leftPressed, rightPressed, upPressed, downPressed); } }
Use the updateGame
method to refresh the Game3DManager
and repaint the canvas.
/** * Update the game state */ protected void updateGame() { score = this.game3DManager.updateGame(); } /** * Render the canvas */ protected void render() { Graphics g = getGraphics(); paint(g); flushGraphics(); }
Use the GameThread
inner class to call the checkKey
and updateGame
methods.
/** * Game loop */ class GameThread extends Thread { private boolean pause = true; private boolean stop = false; private boolean started = false; public void requestPlay() { this.pause = false; if (!started) { this.start(); this.started = true; } } public void requestPause() { this.pause = true; } public void requestStop() { this.stop = true; } public void run() { long time = 0; long delay = 10; while (!stop) { time = System.currentTimeMillis(); if (!pause) { checkKeys(); updateGame(); render(); } time = delay - (System.currentTimeMillis() - time); try { Thread.sleep((time < 0 ? 0 : time)); } catch (InterruptedException e) { } } } }
To implement the Game3DManager
class, which constructs
the 3D scene graph for the game:
In the Game3DManager
class constructor, create an instance of the World
class and build up the 3D scene.
public Game3DManager(int canvasWidth, int canvasHeight) { this.numberOfAliens = 10; this.score = 0; this.canvasWidth = canvasWidth; this.canvasHeight = canvasHeight; this.graphics3D = Graphics3D.getInstance(); rnd = new Random(); scene = new World(); // create scene graph buildScene(); nextTimeToAnimate = scene.animate(appTime); }
Add the space
backdrop to the scene with the addBackground
method.
private void addBackground() { Background backGnd = new Background(); Image2D backIm = loadImage2D("/game/background.png"); if (backIm != null) { backGnd.setImage(backIm); } else { backGnd.setColor(0x000000); } scene.setBackground(backGnd); }
Add light to
the scene with the addLights
method.
private void addLights() { Light light = new Light(); // default white, directional light light.setIntensity(2.5f); // make it a bit brighter light.setOrientation(-65.0f, 1.0f, 0, 0); // pointing down and into scene.addChild(light); }
Use the setFirePressed
method to find out whether the player is
facing any of the aliens. The method uses the collision detection
techniques provided by the Mobile 3D Graphics API.
public void setFirePressed() { RayIntersection ri = new RayIntersection(); float[] camPos = playerCamera.getPosition(); // camera's current // position float[] camDir = playerCamera.getDirection(); // camera's current // direction if (scene.pick(-1, camPos[0], camPos[1], camPos[2], camDir[0], camDir[1], camDir[2], ri)) { // hit something? Node selected = ri.getIntersected(); if (selected instanceof Mesh) { Mesh m = (Mesh) selected; m.setAppearance(0, AlienModel.getFrozenAppearance()); m.setPickingEnable(false); score += 10; numberOfAliens--; } } }