In this chapter we will create the the last class to add to breakout, the BallController.
Topics Covered in this Chapter:
Creating The Ball Controller
Detecting Collisions
Adding Sound Effects
The BallController class is the last class we need to create. The BallController
is responsible for controlling the ball movement, handling collisions, playing
sound effects, and rendering the ball. The BallController requires access to
a Level object and a PaddleController object to do collisions with the ball.
It also requires a SoundManager and access to the device. Take a look at the
BallController from the chapter 6 code like the previous classes it starts with
some defines. The SCREEN_MAX_X, SCREEN_MIN_X, SCREEN_MAX_Y, and SCREEN_MIN_Y
define the ball space in the view. The mins and maxes are the edges of play,
we will set the ball to bonce off these edges.
The BallController init requires the SoundManager,
the Level, the PaddleController, and the device. Init
loads the ball model and the sound effect files, as well as sets ball movement
defualt values.
bool BallController::init(SoundManager* sounds, Level*
level, PaddleController* paddle, LPDIRECT3DDEVICE9 device){
//pointer to the sound manager
mySounds = sounds;
//pointer to the paddle
myPaddle = paddle;
//pointer to the level
myLevel = level;
ballX = 0.0f;
ballY = 0.0f;
ballXMovement = 0.0f;
ballYMovement = 0.0f;
//get the size of the paddle
sizeOfPaddle = myPaddle->getWidth();
//load the ball model
ball = new Model();
ball->loadModel(device, "ball.x");
ball->setScale(D3DXVECTOR3(0.5f,0.5f,0.5f));
//Load the sound effects
paddleSound = mySounds->loadFile("hitpaddle.wav");
brickSound = mySounds->loadFile("hitbrick.wav");
return true;
}
The render function sets the position, and renders
the ball model.
For each frame to update, updateFrames function
calls the checkCollide function to handle collisions,
and then adds the ballXMovement and ballYMovement to the ball position.
for (int i=0; i < framesToUpdate; i++){
//check for collide in this frame before we move the ball
checkCollide();
//Move the ball
ballX+= ballXMovement;
ballY+= ballYMovement;
}
}
The final function in the BallController class is checkCollide.
CheckCollide checks all of the possible collision for the ball, and adjusts
the balls movement based on the collisions. It also plays the appropriate collision
sound effects. The collisions are checked against the position the ball would
be on the next frame. The first collisions checked for are against the edges
of the play field, when the left, right, or top of the screen is collided with
the direction of the ball is changed. When the ball goes off the bottom, it
is reset. Next the getTileAtCoords is called with
the new X position and the current Y position, and then current X position and
the new Y position to determine the direction of the collision. If the ball
collides with the new Y position, then the ball hit the top or the bottom of
a brick, if it was the new X position that collided then it was a side that
was collided with. We use this information to reverse the X or Y direction of
the balls movement. The last collision checked is with the paddle. The getPaddleXY
is called to get the paddle's position. If the ball collides with the paddle,
it plays the paddle collide and changes the ball direction to up.
void BallController::checkCollide(){
float newBallX = ballX + ballXMovement;
float newBallY = ballY + ballYMovement;
//check collide with bounds of the screen
if (newBallX > SCREEN_MAX_X || newBallX < SCREEN_MIN_X){
ballXMovement = ballXMovement*(-1);
}
//rebound if it hits the top of the screen
if (newBallY > SCREEN_MAX_Y){
ballYMovement = ballYMovement*(-1);
}
//restart if it goes off the bottom of the screen
if (newBallY < SCREEN_MIN_Y){
restart();
}
//used to get the index of the tile
int* tempX = new int;
int* tempY = new int;
//checks if there is a tile in the balls path
if (myLevel->getTileAtCoords(newBallX, ballY, tempX, tempY) != 0){
//reverse the ball movement
ballXMovement = ballXMovement*(-1);
//destroys the brick collided with
myLevel->destroyBrick(*tempX, *tempY);
//plays the collide sound
mySounds->playSound(brickSound);
} else if (myLevel->getTileAtCoords(ballX, newBallY, tempX, tempY) != 0){
//reverse the ball movement
ballYMovement = ballYMovement*(-1);
//destroys the brick collided with
myLevel->destroyBrick(*tempX, *tempY);
//plays the collide sound
mySounds->playSound(brickSound);
}
//used to get the paddleX and Y
float* paddleX = new float;
float* paddleY = new float;
//get the position of the paddle
myPaddle->getPaddleXY(paddleX, paddleY);
if (newBallY < *paddleY){
if (newBallX > (*paddleX - (sizeOfPaddle / 2.0f)) && newBallX <
(*paddleX + (sizeOfPaddle / 2.0f)) ){
//reverse the ball movement
ballYMovement = ballYMovement*(-1);
//play the paddle sound
mySounds->playSound(paddleSound);
}
}
That concludes the BallController, adding it to the Breakout class, requires
additions to init, updateFrames
and render.
Changes to Breakout Init:
bool Breakout::init(InputManager* input, SoundManager*
sounds, LPDIRECT3DDEVICE9 device){
.....
//create the ball controller
ball = new BallController();
ball->init(sounds,level, paddle, device);
ball->restart();
.....
return true;
}
Changes to Breakout updateFrames:
void Breakout::updateFrames(int numberOfFrames){
//update the paddle
paddle->update(); //update the ball controller
ball->updateFrames(numberOfFrames); if (myInput->keyPress(DIK_ESCAPE)){
message = QUIT;
}
}
Changes to Breakout Render:
void Breakout::render(LPDIRECT3DDEVICE9 device){
//render the background
background->render(device);
//render the level
level->render(device);
//render the ball ball->render(device);
//render the paddle
paddle->render(device);
}
Now that the BallController has been added, compiling and running the project
should provide you with a fully playable breakout game.
Summing Up - Chapter 6
The BallController class is the last class in our breakout game, it handles
the ball movement, but also the game logic. The collisions are simple in this
version, and the ball always bounces at 90 degree angles. Adding changes to
the x and y velocity based on how the ball colides with the paddle would make
the game a little more interesting.