The Bat class

The Bat class, as we will see has several similarities to the Ball class. After all, it's just a moving rectangle. However, the bat in the game needs to be controlled by the player. So, we need to provide a way to communicate what the player is pressing on the screen to the Bat class.

In later projects with more complicated controls, we will let the class itself translate the screen presses. For the Bat class, we will let PongGame handle the touches and just let the Bat class know one of three things: move left, move right, don't move. Let's look at all the variables the Bat class is going to need.

We will need a RectF to hold the position of the bat and a way of sharing the details with the PongGame class. We will call this variable mRect and the solution to sharing it will be identical to the solution from the Ball class- a default access getRect method that returns a RectF object.

We will need to calculate and retain the length of the bat and will do so with a float called mLength. Furthermore, it will be useful to retain, separately from the RectF the horizontal coordinate of the bat and we will do so in the float variable, mXCoord. We will see where this is useful shortly.

In the constructor, we will calculate a suitable movement speed for the bat. This speed will be based on the resolution of the screen and we will retain the value in mBatSpeed float variable.

The screen resolution, specifically the horizontal resolution is not just used in the constructor for the reasons just mentioned but will also be required in other methods of the class. For example, when doing calculations to prevent the bat going off the screen. Therefore, we will store this value in the mScreenX variable.

We already discussed that the PongGame class will keep the Bat class informed about its movement status(left, right or stopped). To handle this we will have three public final int variables, STOPPED, LEFT, RIGHT. They are public, so they can be directly accessed from PongGame (in the touch handling code) and final so they cannot be changed.

The PongGame class will be able to read their values (0,1 and 2) respectively and pass them via a setter method to alter the value of the mBatMoving variable that will be read once per frame in the Bat class to determine how/if to move.

We could have left out these three variables and just passed 1, 2 or 3 via the setter method. But this would rely on us remembering what each of the numbers represented. Having public variables means we don't need to know what the data is, just what it represents. Making the variables final with access to the important variable (mBatMoving) only via a setter maintains encapsulation while removing any ambiguity. Seeing the movement in action when we implement a Bat in the PongGame class will make this clear.

Let's write the code and get the bat working.

Coding the Bat variables

Add the member variables and object instances just inside the class declaration. You will need to import the RectF class also.

class Bat {

    // These are the member variables (fields)
    // They all have the m prefix
    // They are all private
    // because direct access is not required
    private RectF mRect;
    private float mLength;
    private float mXCoord;
    private float mBatSpeed;
    private int mScreenX;

    // These variables are public and final
    // They can be directly accessed by
    // the instance (in PongGame)
    // because they are part of the same
    // package but cannot be changed
    final int STOPPED = 0;
    final int LEFT = 1;
    final int RIGHT = 2;

    // Keeps track of if and how the ball is moving
    // Starting with STOPPED
    private int mBatMoving = STOPPED;
   
}

The member variables we just coded are just as we discussed. Now we can move on to the methods. Add them all one after the other inside the body of the Bat class.

Coding the Bat constructor

Now we can code the constructor which we will soon call from the PongGame constructor right after the Ball constructor is called.

Add the constructor code and then we can go through it.

Bat(int sx, int sy){

   // Bat needs to know the screen
   // horizontal resolution
   // Outside of this method
   mScreenX = sx;

   // Configure the size of the bat based on
   // the screen resolution
   // One eighth the screen width
   mLength = mScreenX / 8;
   // One fortieth the screen height
   float height = sy / 40;

   // Configure the starting location of the bat
   // Roughly the middle horizontally
   mXCoord = mScreenX / 2;
   // The height of the bat
   // off the bottom of the screen
   float mYCoord = sy - height;

   // Initialize mRect based on the size and position
   mRect = new RectF(mXCoord, mYCoord,
               mXCoord + mLength,
               mYCoord + height);

   // Configure the speed of the bat
   // This code means the bat can cover the
   // width of the screen in 1 second
   mBatSpeed = mScreenX;
}

First, notice the passed in parameters, sx, and sy. They hold the screen's resolution (horizontal and vertical). The first line of code initializes mScreenX with the horizontal resolution. Now we will have it available throughout the class.

Next, mLength is initialized to mScreenX divided by 8. The 8 is a little bit arbitrary but makes a decently sized bat. Feel free to make it wider or thinner. Immediately after a local variable height is declared and initialized to sy / 40. The 40 is also fairly arbitrary but the value works well. Feel free to adjust it to have a taller or shorter bat. The reason that the horizontal variable is a member and the vertical variable is local is because we only need the vertical values for the duration of this method.

After this, mXCoord is initialized to half the screens width (mScreenX / 2). We will see this variable in action soon and why it is necessary.

Moving on to the next line, we declare and initialize a local variable called mYCoord. It is initialized to sy – height. This will have the effect of placing the bottom of the bat on the very bottom pixel of the screen.

Now we get to initialize the RectF (mRect) that represents the position of the bat. The four arguments passed in to initialize the left, top, right and bottom coordinates of the RectF, in that order.

Finally, we initialize mBatSpeed with mScreenX. This has the effect of making the bat move at exactly one screen's width per second.

Now we code the getRect method.

// Return a reference to the mRect object
RectF getRect(){
   return mRect;
}

The previous code is identical to the getRect method from the Ball class and will be used to share the bat's RectF with PongGame.

Coding the Bat helper methods

The setMovementState method is the setter that will receive a value from PongGame of either LEFT, RIGHT or STOPPED. All it does is set that value to mBatMoving ready for later use. Add the code for the setMovementState method.

// Update the movement state passed
// in by the onTouchEvent method
void setMovementState(int state){
   mBatMoving = state;
}

As mBatMoving has just got a way of being given a meaningful value, we can now use it to move (or stop) the bat, each frame, in the update method.

Coding the Bat's update method

The update method has some similarities to the ball's update method. The main difference is the series of if statements that check the current values of various member variables to decide which direction (if any) to move. Code the update method shown next and then we can discuss it further:

// Update the bat- Called each frame/loop
void update(long fps){

   // Move the bat based on the mBatMoving variable
   // and the speed of the previous frame
   if(mBatMoving == LEFT){
         mXCoord = mXCoord - mBatSpeed / fps;
   }

   if(mBatMoving == RIGHT){
         mXCoord = mXCoord + mBatSpeed / fps;
   }

   // Stop the bat going off the screen
   if(mXCoord < 0){
         mXCoord = 0;
   }

   else if(mXCoord + mLength > mScreenX){
         mXCoord = mScreenX - mLength;
   }

   // Update mRect based on the results from
   // the previous code in update
   mRect.left = mXCoord;
   mRect.right = mXCoord + mLength;
}

The first if statement is if(mBatMoving == LEFT). This will be true if the setMovementState method had previously been called with the LEFT value. Inside the if block we see this code:

mXCoord = mXCoord - mBatSpeed / fps;

This line of code has the effect of moving the bat to the left relative to the current frame rate. The next if statement does exactly the same except to the right.

The third if statement has the condition mXCoord < 0. This is detecting if the left-hand side of the bat has moved off the left-hand side of the screen. If it has, the single line of code inside the block sets it back to zero, locking the bat on the screen.

The else if statement that follows has the same effect but for the right-hand side of the bat going off the right-hand side of the screen. The reason the code is more complex is that we can't just use mXCoord.

The else if statement condition, mXCoord + mLength > mScreenX, compares the right-hand edge to the screen width and inside the if block, mXCoord = mScreenX – mLength sets the position back to the farthest right pixel possible without being off-screen.

The final two lines of code in the update method sets the left and right-hand coordinates of mRect to these newly updated positions. We don't need to bother with the vertical coordinates (as we did with the ball) because they never change.

Using the Bat Class

Now for the good bit. Initialize the bat in the PongGame constructor like this highlighted code.

// Initialize the bat and ball
mBall = new Ball(mScreenX);
mBat = new Bat(mScreenX, mScreenY);

Update the bat each frame in the update method as shown highlighted next.

private void update() {
   // Update the bat and the ball
   mBall.update(mFPS);
   mBat.update(mFPS);
}

Finally, before we can run the game again, add this highlighted code in the PongGame draw method.

// Draw the bat and ball
mCanvas.drawRect(mBall.getRect(), mPaint);
mCanvas.drawRect(mBat.getRect(), mPaint);

Run the game and you will see we have a static bat and a static ball. Now we can code the onTouchEvent method.

Using the Bat Class

Let's make the bat moveable.

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

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