Reusing the Pong engine

Feel free to copy and paste all the code in this section. It is nearly identical to the structure of the Pong game. What will vary is the other classes we will create (Bullet and Bob) as well as the way that we handle player input, timing, updating and drawing within the BulletHellGame class.

As you proceed with this section glance over the code to notice subtle but important differences which I will also point out to you as we proceed.

Coding the BulletHellActivity

Paste and examine this code into the BulletHellActivity class.

import android.app.Activity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;


// This class is almost exactly 
// the same as the Pong project
public class BulletHellActivity extends Activity {

    // An instance of the main class of this project
    private BulletHellGame mBHGame;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get the screen resolution
        Display display = getWindowManager().
                          getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        // Call the constructor(initialize) 
        // the BulletHellGame instance
        mBHGame = new BulletHellGame(this, size.x, size.y);
        setContentView(mBHGame);
    }

    @Override
    // Start the main game thread 
    // when the game is launched
    protected void onResume() {
        super.onResume();

        mBHGame.resume();
    }

    @Override
    // Stop the thread when the player quits
    protected void onPause() {
        super.onPause();

        mBHGame.pause();
    }
}

It is very similar to the previous project except for the BulletHellGame object instead of a PongGame object declaration. In addition, the BulletHellGame object (mBHGame) is therefore used in the call to setContentView as well as in onResume and onPause to start and stop the thread in the BulletHellGame class which we will code next.

There are lots of errors in Android Studio but only because the code refers to the BulletHellGame class that we haven't coded yet. We will do that now.

Coding the BulletHellGame class

Paste this next code into the BulletHellGame class. It is exactly the same structure as the previous game. Familiarize yourself with it again by pasting and reviewing it a section at a time. Make note of the code structure and the blank methods that we will soon add new bullet-hell-specific code to.

Add the import statements and alter the class declaration to handle a thread (implement the Runnable interface) and extend SurfaceView.

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;

class BulletHellGame extends SurfaceView implements Runnable{
}

Coding the member variables

Add the member variables after the class declaration

class BulletHellGame extends SurfaceView implements Runnable{

    // Are we currently debugging
    boolean mDebugging = true;

    // Objects for the game loop/thread
    private Thread mGameThread = null;
    private volatile boolean mPlaying;
    private boolean mPaused = true;

    // Objects for drawing
    private SurfaceHolder mOurHolder;
    private Canvas mCanvas;
    private Paint mPaint;

    // Keep track of the frame rate
    private long mFPS;
    // The number of milliseconds in a second
    private final int MILLIS_IN_SECOND = 1000;

    // Holds the resolution of the screen
    private int mScreenX;
    private int mScreenY;

    // How big will the text be?
    private int mFontSize;
    private int mFontMargin;

    // These are for the sound
    private SoundPool mSP;
    private int mBeepID = -1;
    private int mTeleportID = -1;
}

All the member variables were also present in the PongGame class and have exactly the same usage. The previous code includes a few comments as a reminder.

Coding the BulletHellGame constructor

Add the constructor after the members but inside the closing curly brace of the class.

// This is the constructor method that gets called
// from BullethellActivity
public BulletHellGame(Context context, int x, int y) {
   super(context);

   mScreenX = x;
   mScreenY = y;
   // Font is 5% of screen width
   mFontSize = mScreenX / 20;
   // Margin is 2% of screen width
   mFontMargin = mScreenX / 50;

   mOurHolder = getHolder();
   mPaint = new Paint();


   // Initialize the SoundPool
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
         AudioAttributes audioAttributes = 
               new AudioAttributes.Builder()
               .setUsage(AudioAttributes.USAGE_MEDIA)
      
               .setContentType
               (AudioAttributes.CONTENT_TYPE_SONIFICATION)
               .build();

      mSP = new SoundPool.Builder()
            .setMaxStreams(5)
            .setAudioAttributes(audioAttributes)
            .build();
   } else {
      mSP = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
   }


   try{
         AssetManager assetManager = context.getAssets();
         AssetFileDescriptor descriptor;

         descriptor = assetManager.openFd("beep.ogg");
         mBeepID = mSP.load(descriptor, 0);

         descriptor = assetManager.openFd("teleport.ogg");
         mTeleportID = mSP.load(descriptor, 0);

   }catch(IOException e){
      Log.e("error", "failed to load sound files");
   }

   startGame();
}

The constructor code we have just seen contains nothing new. The screen resolution is passed in as parameters, the corresponding member variables (mScreenX and mScreenY) are initialized and the SoundPool object is initialized then the sound effects are loaded into memory. Notice that we call the startGame method at the end.

Coding the BulletHellGame methods

Add these four empty methods and the identically implemented run method to handle the game loop.

// Called to start a new game
public void startGame(){
}

// Spawns ANOTHER bullet
private void spawnBullet(){
}

// Handles the game loop
@Override
public void run() {
   while (mPlaying) {

          long frameStartTime = System.currentTimeMillis();

                   if(!mPaused){
                         update();
                         // Now all the bullets have been moved
                         // we can detect any collisions
                         detectCollisions();

                   }

                   draw();

                   long timeThisFrame = System.currentTimeMillis() 
                         - frameStartTime;
                   if (timeThisFrame >= 1) {
                         mFPS = MILLIS_IN_SECOND / timeThisFrame;
                   }

   }
}


// Update all the game objects
private void update(){
}

private void detectCollisions(){
}

The previous methods we have seen before except for one. We have just coded a spawnBullet method that we can call each time we want to spawn a new bullet. At this point, the method contains no code. We will add code to these methods over this chapter and the next.

Coding draw and onTouchEvent

Add the draw and the onTouchEvent methods that are shown next.

private void draw(){
   if (mOurHolder.getSurface().isValid()) {
         mCanvas = mOurHolder.lockCanvas();
      mCanvas.drawColor(Color.argb(255, 243, 111, 36));
      mPaint.setColor(Color.argb(255, 255, 255, 255));

      // All the drawing code will go here

      if(mDebugging) {
            printDebuggingText();
      }

      mOurHolder.unlockCanvasAndPost(mCanvas);
   }
}

@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
   return true;
}

The draw method just clears the screen with a plain color and sets the paint color to white ready for drawing the bullets. Note the call to printDebuggingText when the mDebugging variable is set to true. We also added an empty (apart from return statement) method for onTouchEvent ready to add code to handle the player's input.

Coding pause, resume, and printDebuggingText

These next three methods, just like all the previous methods, serve exactly the same purpose as they did in the Pong project. Add the pause, resume, and printDebuggingText methods.

public void pause() {
   mPlaying = false;
   try {
         mGameThread.join();
   } catch (InterruptedException e) {
         Log.e("Error:", "joining thread");
   }
}

public void resume() {
   mPlaying = true;
   mGameThread = new Thread(this);
   mGameThread.start();
}

private void printDebuggingText(){
   int debugSize = 35;
   int debugStart = 150;
   mPaint.setTextSize(debugSize);

   mCanvas.drawText("FPS: " + mFPS , 
         10, debugStart + debugSize, mPaint);

}

The printDebuggingText method simply draws the current value of mFPS to the screen. This will be interesting to monitor when there are vast numbers of bullets bouncing all over the place. Two new local variables are also declared and initialized (debugSize and debugStart) they are used to programmatically position and scale the debugging text as it obviously will vary from the HUD text which will be drawn in the draw method.

Testing the Bullet Hell engine

Run the game and you will see we have set up a simple game engine that is virtually identical to the Pong game engine. It doesn't do anything yet except loop around measuring the frames per second, but it is ready to start drawing and updating objects.

Testing the Bullet Hell engine

Now we can focus on building the new game and learning about Java arrays. Let's start with a class that will represent each one of the huge numbers of bullets we will spawn.

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

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