Implementing the game logic and screen

The MIDlet contains three classes needed to manage the game logic and create the game screen:

GameStatusListener

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);
}

GameCanvasView

To implement the GameCanvasView class, which draws the game elements on the screen:

  1. 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);
            }
        }
  2. 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);
            }
        }
  3. 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();
        }
  4. 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) {
                    }
                }
            }
        }

Game3DManager

To implement the Game3DManager class, which constructs the 3D scene graph for the game:

  1. 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);
        }
  2. 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);
    
        }
  3. 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);
    
        }
  4. 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--;
                }
            }
    
        }