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.
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 if
– else if
– else 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.
3.149.214.32