Coding the GameState

The GameState class has exactly the same role as in the previous project. Obviously, however, the details of the state in this project is different. In the previous project we had score, high score lasers and aliens; in this one we have time, multiple fastest times and which level is being played. The GameState class also takes care of knowing (and sharing) the current state of paused, playing, drawing, thread running, etc.

Create a new class called GameState and add the member variables and constructor as shown next.

import android.content.Context;
import android.content.SharedPreferences;

final class GameState {
    private static volatile boolean 
            mThreadRunning = false;
    
    private static volatile boolean mPaused = true;
    private static volatile boolean mGameOver = true;
    private static volatile boolean mDrawing = false;
    private EngineController engineController;

    private int mFastestUnderground;
    private int mFastestMountains;
    private int mFastestCity;
    private long startTimeInMillis;

    private int mCoinsAvailable;
    private int coinsCollected;

    private SharedPreferences.Editor editor;

    private String currentLevel;

    GameState(EngineController gs, Context context) {
        engineController = gs;
        SharedPreferences prefs = context
                .getSharedPreferences("HiScore",
                        Context.MODE_PRIVATE);

        editor = prefs.edit();
        mFastestUnderground = prefs.getInt(
                "fastest_underground_time", 1000);
        mFastestMountains = prefs.getInt(
                "fastest_mountains_time", 1000);
        mFastestCity = prefs.getInt(
                "fastest_city_time", 1000);
    }
}

We have Boolean variables to represent whether the game thread is running, player has paused, game is over or currently drawing. As in the previous project we also have an EngineController reference so GameState can reinitialize a game/level directly.

Next up we have three int variables to hold the fastest time on each of the three levels. The startTimeInMillis variable will be initialized each time a level is attempted to record the time the level was started so it is possible to calculate how long the level took.

There are two more int members to hold the number of coins it is possible to collect in a level and the number of coins actually collected. They are mCoinsAvailable and coinsCollected.

The final two members in the previous code is an instance of SharedPrefferences.Editor for writing new high scores and a String which will represent the current level to be played, City, Underground or Mountains.

Now add this quite long list of getters and setters to the GameState class.

void coinCollected() {
   coinsCollected++;
}

int getCoinsRemaining() {
   return mCoinsAvailable - coinsCollected;
}

void coinAddedToLevel() {
   mCoinsAvailable++;
}

void resetCoins() {
   mCoinsAvailable = 0;
   coinsCollected = 0;
}

void setCurrentLevel(String level) {
   currentLevel = level;
}

String getCurrentLevel() {
   return currentLevel;
}

void objectiveReached() {
   endGame();
}

int getFastestUnderground() {
   return mFastestUnderground;
}

int getFastestMountains() {
   return mFastestMountains;
}

int getFastestCity() {
   return mFastestCity;
}

A detailed description of each of the methods we just added would be somewhat laborious because they each do just one thing.

  • Set a value(s)
  • Return a value
  • Call another method

It is however, well worth closely inspecting each method's name to aid understanding as we proceed.

Next, add three more methods to the GameState class for starting a new game, getting the current time and taking action when the player dies.

void startNewGame() {
   // Don't want to be handling objects while
   // clearing ArrayList and filling it up again
   stopEverything();
   engineController.startNewLevel();
   startEverything();
   startTimeInMillis = System.currentTimeMillis();
}

int getCurrentTime() {
   long MILLIS_IN_SECOND = 1000;
   return (int) ((System.currentTimeMillis()
         - startTimeInMillis) / MILLIS_IN_SECOND);
}

void death() {
   stopEverything();
   SoundEngine.playPlayerBurn();
}

The startNewGame method calls the stopEverything method. We will code the stopEverything method soon. The next line of code uses the GameController reference to call the startNewLevel method on the GameEngine class. Once the startNewLevel method has done its work we call the startEverything method (which we will code soon) to get things going again. The reason we do these three steps is because otherwise we will be trying to update and draw objects at the same time as the GameEngine is also deleting and reinitializing them. This would be bound to cause a crash. The last thing we do in startNewGame is initialize the startTimeInMillis variable with the current time.

The getCurrentTime method shares the current time. Note that it takes the start time from the current time and divides the result by one thousand. This is because we want the player to see their time in seconds not milliseconds.

The death method simply calls stopEverything and then uses the SoundEngine to play a death sound.

Now code the endGame method and then we will discuss it.

private void endGame() {

   stopEverything();
   int totalTime =
              ((mCoinsAvailable - coinsCollected)
                          * 10)
                          + getCurrentTime();

   switch (currentLevel) {

      case "underground":
         if (totalTime < mFastestUnderground) {
            mFastestUnderground = totalTime;
            // Save new time

            editor.putInt("fastest_underground_time",
                  mFastestUnderground);

            editor.commit();
         }
         break;
      case "city":
         if (totalTime < mFastestCity) {
            mFastestCity = totalTime;
            // Save new time
            editor.putInt("fastest_city_time",
                  mFastestCity);

            editor.commit();
         }
         break;
      case "mountains":
         if (totalTime < mFastestMountains) {
            mFastestMountains = totalTime;
            // Save new time
            editor.putInt("fastest_mountains_time",
                  mFastestMountains);

            editor.commit();
         }
         break;
   }
}

The first line of code in endGame calls stopEverything so the game engine will halt updating and drawing.

Next, a local variable, totalTime is declared and initialized. The total time (as you might remember from Chapter 22: Platform Game: Bob was in a hurry section) is calculated by the total time the player took added to a penalty for each coin that the player failed to collect.

Next in the endGame method we enter a switch block where the condition is the currentLevel String. The first case is when the underground level has been played. The code uses an if statement to check if totalTime is less than mFastestUnderground. If it is then the player has a new fastest time. The editor.putInt and editor.commit methods of the SharedPrefferences.Editor instance are then used to save the new record for posterity.

The next two case blocks do the same thing for the city then the mountains levels.

Now code the final methods for the GameState class.

void stopEverything() {// Except the thread
   mPaused = true;
   mGameOver = true;
   mDrawing = false;
}

private void startEverything() {
   mPaused = false;
   mGameOver = false;
   mDrawing = true;
}

void stopThread() {
   mThreadRunning = false;
}

boolean getThreadRunning() {
   return mThreadRunning;
}

void startThread() {
   mThreadRunning = true;
}

boolean getDrawing() {
   return mDrawing;
}

boolean getPaused() {
   return mPaused;
}

boolean getGameOver() {
   return mGameOver;
}

The final getters and setters control when the game engine does certain tasks like start/stop the thread and call update and/or draw. Familiarize yourself with their names and which members they interact with.

Let's make some noise.

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

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