Implementing the UI elements

MenuList class

Figure 50: Menu list

The menu list is the screen shown after the splash screen, or when the game is over, or when the user presses a nongame key during the game (and thereby pauses it). If the game has been paused, there is an extra menu item, Continue, at the top of the list.

  1. Create the MenuList class file.

  2. Import the required classes.

    // unnamed package
    import javax.microedition.lcdui.*;
    
  3. Set MenuList to extend List and implement CommandListener.

    class MenuList
        extends List
        implements CommandListener
    {
        private SheepdogMIDlet midlet;
        private Command exitCommand;
        private boolean gameActive = false;
  4. Create the menu listing for the game.

        MenuList(SheepdogMIDlet midlet)
        {
            super("Sheepdog", List.IMPLICIT);
            this.midlet = midlet;
            append("New game", null);
            append("High score", null);
            append("Instructions", null);
            exitCommand = new Command("Exit", Command.EXIT, 1);
            addCommand(exitCommand);
            
            setCommandListener(this);
        }
    
    
  5. Create a method to activate the game.

        void setGameActive(boolean active)
        {
            if (active && !gameActive)
            {
                gameActive = true;
                insert(0, "Continue", null);
            }
            else if (!active && gameActive)
            {
                gameActive = false;
                delete(0);
            }
        }
    
    
  6. Create a method for monitoring the commands used for the menu.

        public void commandAction(Command c, Displayable d)
        {
            if (c == List.SELECT_COMMAND)
            {
                int index = getSelectedIndex();
                if (index != -1)  // should never be -1
                {
                    if (!gameActive)
                    {
                        index++;
                    }
                    switch (index)
                    {
                    case 0:   // Continue
                        midlet.menuListContinue();
                        break;
                    case 1:   // New game
                        midlet.menuListNewGame();
                        break;
                    case 2:   // High score
                        midlet.menuListHighScore();
                        break;
                    case 3:
                        midlet.menuListInstructions();
                        break;
                    default:
                        // can't happen
                        break;
                    }
                }
            }
            else if (c == exitCommand)
            {
                midlet.menuListQuit();
            }
        }
    }

InstructionsScreen class

Figure 51: Instructions screen

The instructions screen displays an instruction text to the user.

  1. Create the InstructionsScreen class file.

  2. Import the required classes.

    // unnamed package
    import javax.microedition.lcdui.*;
    
  3. Set InstructionsScreen to extend Form and implement CommandListener. Write the String containing the instructions.

    class InstructionsScreen
        extends Form
        implements CommandListener
    {
        private final SheepdogMIDlet midlet;
        private final Command backCommand;
    
        private static final String instructions =
            "Herd the sheep into the fold as quickly as you can.\n" +
            "Sheep won't leave the fold once they've entered it.\n" +
            "If they're not behaving, bark using the Fire key!";
    
    
  4. Write the code for the InstructionsScreen object.

        InstructionsScreen(SheepdogMIDlet midlet)
        {
            super("Instructions");
            this.midlet = midlet;
            append(new StringItem(null, instructions));
            backCommand = new Command("Back", Command.BACK, 1);
            addCommand(backCommand);
            setCommandListener(this);
        }
        
  5. Create a method for monitoring the use of instructionsBack command in the Midlet.

        public void commandAction(Command c, Displayable d)
        {
            midlet.instructionsBack();
        }
    }
    

HighScoreScreen class

Figure 52: High-score screen

The high-score screen is used to display the current high score (the best time so far). Since the initial placing of the sheep is random, this isn't actually very meaningful in this game.

  1. Create the HighScoreScreen class file.

  2. Import the required classes.

    // unnamed package
    import javax.microedition.lcdui.*;
    
  3. Set HighScoreScreen to extend Form and implement CommandListener.

    class HighScoreScreen
        extends Form
        implements CommandListener
    {
        private final SheepdogMIDlet midlet;
        private final Command backCommand;
  4. Write the code that will create the high score screen.

        HighScoreScreen(SheepdogMIDlet midlet)
        {
            super("High score");
            this.midlet = midlet;
    
            long bestTime = midlet.getBestTime(); 
            String text = (bestTime == -1) ? "none yet"
                                           : (Long.toString(bestTime) + "s");
            append(new StringItem("Best time", text));
    
            backCommand = new Command("Back", Command.BACK, 1);
            addCommand(backCommand);
            setCommandListener(this);
        }
    
        
  5. Create a method for monitoring the use of highScoreBack command in the Midlet.

        public void commandAction(Command c, Displayable d)
        {
            midlet.highScoreBack();
        }
    }

GameOverScreen class

Figure 53: Game-over screen

This screen is displayed when the player gets the fifth sheep into the fold. It shows the player's time, and indicates whether it's the new best time or shows the player what the best time is. When it appears, the screen flashes for a second and one of two short MIDI tunes is played.

Note the useful trick for drawing outlined text: first draw it four times in the outline color, offset up, down, left, and right. Then draw it in the text color at its normal location. Beware of using this in the main game screen, as text drawing can be quite slow and this makes it five times slower!

  1. Create the GameOverScreen class file.

  2. Import the required classes.

    // unnamed package
    import javax.microedition.lcdui.*;
    
  3. Set GameOverScreen to extend Canvas.

    class GameOverScreen
        extends Canvas
    {
        private final SheepdogMIDlet midlet;
        private boolean wasBestTime;
        private long time;
        private long bestTime;
    
    
  4. Create the GameOverScreen object. Include the logic for checking if the last game created a high score or not.

        GameOverScreen(SheepdogMIDlet midlet, long time)
        {
            super();
            this.midlet = midlet;
            this.time = time;
            setFullScreenMode(true);
    
            if (midlet.checkBestTime(time))
            {
                wasBestTime = true;
                bestTime = time;
                SoundEffects.getInstance().startHighScoreSound();
            }
            else
            {
                wasBestTime = false;
                bestTime = midlet.getBestTime();
                SoundEffects.getInstance().startGameOverSound();
            }
            midlet.flashBacklight(1000);    // 1 second
        }
    
    
  5. Create the method for painting the screen.

        public void paint(Graphics g)
        {
            int width = getWidth();
            int height = getHeight();
    
            // clear screen to green
            g.setColor(0x0000FF00);
            g.fillRect(0, 0, width, height);
    
            // Write message. We use a trick to make outlined text: we draw it
            // offset one pixel to the top, bottom, left & right in white, then
            // centred in black.
            g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,
                                   Font.STYLE_BOLD,
                                   Font.SIZE_LARGE));
            int centerX = width / 2;
            int centerY = height / 2;
            g.setColor(0x00FFFFFF);   // white
            drawText(g, centerX, centerY - 1);
            drawText(g, centerX, centerY + 1);
            drawText(g, centerX - 1, centerY);
            drawText(g, centerX + 1, centerY);
            g.setColor(0x00000000);   // black
            drawText(g, centerX, centerY);
        }
  6. Create a method for drawing text on the screen.

        private void drawText(Graphics g, int centerX, int centerY)
        {
            int fontHeight = g.getFont().getHeight();
            int textHeight = 3 * fontHeight;
            int topY = centerY - textHeight / 2;
            g.drawString("GAME OVER",
                         centerX,
                         topY,
                         Graphics.HCENTER | Graphics.TOP);
            g.drawString("Time: " + time + "s",
                         centerX,
                         topY + fontHeight,
                         Graphics.HCENTER | Graphics.TOP);
            g.drawString(wasBestTime ? "New best time!" :
                                       ("Best time: " + bestTime + "s"),
                         centerX,
                         topY + 2 * fontHeight,
                         Graphics.HCENTER | Graphics.TOP);
        }
        
        public void keyPressed(int keyCode)
        {
            midlet.gameOverDone();
        }
    }