Coding the UIController class

This class will have the same purpose as the class of the same name did in the previous project. It will also look very similar too.

Add a new class called UIController and add the member variables, constructor and addObserver method.

import android.graphics.Point;
import android.graphics.Rect;
import android.view.MotionEvent;

import java.util.ArrayList;

class UIController implements InputObserver {

    private float mThird;

    private boolean initialPress = false;

    UIController(GameEngineBroadcaster b, Point size) {
        // Add as an observer
        addObserver(b);

        mThird = size.x / 3;
    }

    
    void addObserver(GameEngineBroadcaster b) {
        b.addObserver(this);
    }
}

The float mThird variable will help us to divide the screen up vertically into thirds. The player will then be able to tap a portion of the screen to choose the level that they want to play. The initialPress Boolean is used in a workaround to avoid a bug/glitch. Sometimes when the game ends the menu will immediately register the player's touch causing a new level to start instantly rather than allowing them to view the menu screen at their leisure. By ignoring the very first touch we avoid this problem.

Tip

This is a hack and not a good solution to go into a finished game. Unfortunately, the solution would require at least another chapter and I am running out of space. In chapter 26 I suggest some resources to continue your learning. Be sure to look into the State pattern to improve all the projects and as a solution for this hack.

In the constructor we call the addObserver method and initialize the mThird variable to a third of the screen's width. In the addObserver method the code uses the GameEngineBroadcaster reference to add an observer to GameEngine.

We need to add an observer each time a new game is started, and the game objects are rebuilt because the observer list is cleared. The addObserver method allows us to re-add an observer rather than just add it in the constructor.

Now add the handleInput method which receives the MotionEvent, the GameState and the ArrayList which contains the button positions.

@Override
public void handleInput(MotionEvent event,
   GameState gameState,
   ArrayList<Rect> buttons) {

   int i = event.getActionIndex();
   int x = (int) event.getX(i);

   int eventType = event.getAction()
               & MotionEvent.ACTION_MASK;

   if (eventType == MotionEvent.ACTION_UP ||
               eventType == MotionEvent.ACTION_POINTER_UP) {

        // If game is over start a new game
        if (gameState.getGameOver() && initialPress) {

               if (x < mThird) {
                     gameState.setCurrentLevel("underground");
                     gameState.startNewGame();
               } else if (x >= mThird && x < mThird * 2) {
                      gameState.setCurrentLevel("mountains");
                      gameState.startNewGame();
               } else if (x >= mThird * 2) {
                      gameState.setCurrentLevel("city");
                      gameState.startNewGame();
            }
        }
      initialPress = !initialPress;
   }
}

As we did in the previous project we handle input by accessing the event at the index which triggered the current action. There is an ifelse ifelse if structure where the code detects which level was pressed. These are the only touches that need to be handled. The buttons will be handled by the PlayerController component class. After an ACTION_UP has been detected, notice also that the rest of the code is wrapped in an if condition that tests whether the game is over and initialPress is false. Outside this structure all ACTION_UP events will switch the value of initialPress. This means that the last stray touch of game-play won't dismiss the menu screen as soon as it starts.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.214.32