Chapter 11. Ball-and-Paddle Games

Ball-and-Paddle Games

The next genre of games dates back to the first video game: Pong. This simple game started the arcade revolution in the 70s.

These games all involve a simple ball that bounces off walls and a paddle that the player controls. The player tries to not let the ball get past the paddle.

The first game you will build has a single paddle and a ball. The second game features a second, computer-controlled paddle and an artificially intelligent opponent. The third game in this chapter has the player trying to hit blocks with the ball, like the classic arcade game Breakout. The final game moves the paddle and ball concept into the third dimension.

Wall Ball

Wall BallExample file: Wallball.fla

The first game is called Wall Ball. It features a single, player-controlled paddle and three walls that the ball can bounce off of. The fourth wall is open. The player’s task is to not let the ball get past the paddle and through the open wall. Figure 11.1 shows this simple game.

The Wall Ball game features a ball, a paddle, and a wall.

Figure 11.1. The Wall Ball game features a ball, a paddle, and a wall.

Project Goal

The goal is to build a game where a moving ball reflects off walls and a paddle. The paddle should follow the vertical location of the mouse. When the ball gets past the paddle and reaches the edge of the screen, the game should end. Also, when the ball hits the paddle, it should increase in speed slightly.

Approach

The most complex part of this game is getting the ball to accurately reflect off the walls. Many programmers over-simplify this, not taking into account the width of the ball and its speed. As a result, the ball can appear to reflect at a point beyond the wall.

The code needs to look for the situation in which the ball has moved beyond the wall. Then it will determine how far beyond the wall the ball is. Because the ball moves at several pixels per frame, it can easily overshoot the wall by several pixels.

After you know how far past the wall the ball is, you can change its direction, and then place the ball at the appropriate distance from the correct side of the wall. Figure 11.2 shows a diagram of how this works.

The diagram explains how the ball is repositioned after a collision with a wall.

Figure 11.2. The diagram explains how the ball is repositioned after a collision with a wall.

Collisions with the paddle are treated just like collisions with a wall. The only difference is that you must make sure the vertical position of the paddle is such that the ball will hit it.

When a ball passes the horizontal location of the paddle, but the paddle is not there, you set a variable flag so that you know the paddle was missed. This way, you won’t give the player a second chance to hit the ball as it continues on its journey to the edge of the screen.

Preparing the Movie

The only graphics needed for this game are the ball, the paddle, and the walls. The wall graphics are actually not even used by the code, because the actual game boundaries are in the code as number constants.

Writing the Code

You need only three functions for this game. Check out the example movie, Wallball.fla. All three of these are called from an “actions” movie clip:

<LINELENGTH>90</LINELENGTH>
onClipEvent(load) {
    _root.initGame();
}

onClipEvent(enterFrame) {
    _root.moveBall();
    _root.movePaddle();
}

The functions are stored in the main timeline. The first one, “initGame,” stores the location of the ball into “x” and “y.” It starts “dx” and “dy,” which are the horizontal and vertical speeds of the ball, at 5 for each. Then, the function sets a bunch of constants that determine the positions of each wall.

This function also gets the radius of the ball, a value that will be useful in the “moveBall” function. The “passedPaddle” variable is a flag that is set to true after the player misses. You should also take this opportunity to turn off the cursor, because it would be a distraction to the player.

<LINELENGTH>90</LINELENGTH>
function initGame() {
    // get start position of the ball
    x = ball._x;
    y = ball._y;

    // set initial speed
    dx = 5;
    dy = 5;

    // set constants
    rightWall = 550;
    leftWall = 0;
    topWall = 0;
    bottomWall = 400;
    ballRadius = ball._width/2;
    passedPaddle = false;

    // hide cursor
    Mouse.hide();
}

The “movePaddle” function is the workhorse of this game. It starts by changing “x” and “y” to “dx” and “dy” to get the new location of the ball Writing the Code. Then, it checks to see whether the ball has gone past the right wall Writing the Code. It adds the radius of the ball to the location of the ball to get the exact position of the right edge of the ball. If the ball has passed the wall, the “movePaddle” function calculates by how much and stores that in “overshoot.” The location of the ball is then moved back by twice “overshoot.” The direction of the ball is changed by multiplying “dx” by –1. This effectively changes the sign of “dx.” So if it was 5 before hitting the wall, it becomes –5.

Next, the code checks to see whether the ball has passed the bottom wall Writing the Code. This is similar to the previous segment, except that “y” and “dy” are used instead of “x” and “dx.”

When the code checks the top wall, some of the calculations are a little different Writing the Code. To determine the location of the top edge of the ball, the radius of the ball is subtracted from the location of the ball. Then, “overshoot” is calculated by subtracting the location of the top edge of the ball from the wall’s location.

To detect whether the ball has hit the paddle, the code first calculates the location of the right edge of the paddle Writing the Code. Then, if the ball is far enough to the left, it calculates the top and bottom of the paddle and determines whether the ball and paddle intersect Writing the Code.

If the ball hits the paddle, the paddle behaves like any other wall. However, it also increases the speed of the ball by 5% Writing the Code. If the ball misses the wall, the only action taken at this point is to set “passedPaddle” to true.

If “passedPaddle” is true and the ball is where the left wall should be, the game is over Writing the Code. The cursor is set back to normal, and the movie jumps to the “game over” frame.

The “moveBall” function ends by setting the location of the ball movie clip to “x” and “y.”

Note

Note

The operator “*=” works like “+=,” except that it multiplies the original variable by the specified amount. So if “a” is 5, the line “a *= 3” changes “a” to 15. Likewise, if you use “a *= –1”, then “a” becomes –5. Using “*= –1” is a quick way to change the sign of a number.

<LINELENGTH>90</LINELENGTH>
    function moveBall() {
Note    // change x and y
        x += dx;
        y += dy;

Note    // check right wall
        if (x+ballRadius > rightWall) {
            overshoot = (x+ballRadius) - rightWall;
            x -= overshoot*2;
            dx *= -1;
        }

Note    // check bottom
        if (y+ballRadius > bottomWall) {
            overshoot = (y+ballRadius) - bottomWall;
            y -= overshoot*2;
            dy *= -1;
        }

Note    // check top
        if (y-ballRadius < topWall) {
            overshoot = topWall - (y-ballRadius);
            y += overshoot*2;
            dy *= -1;
        }

Note    // is it where it should hit the paddle?
        paddleRight = paddle._x+(paddle._width/2);
        if ((x-ballRadius < paddleRight) and !passedPaddle) {

Note        // is the paddle there?
           paddleTop = paddle._y-(paddle._height/2);
           paddleBottom = paddle._y+(paddle._height/2);
           if ((y > paddleTop) and (y < paddleBottom)) {

               // hit paddle
               overshoot = paddleRight - (x-ballRadius);
               x += overshoot*2;
               dx *= -1;

Note           // speed up
               dx *= 1.05;
               dy *= 1.05;
           } else {

               // missed paddle, don't check again
               passedPaddle = true;
           }
        }

Note    // check left wall
        if ((x-ballRadius < leftWall) and passedPaddle) {
            Mouse.show();
            gotoAndPlay("game over");
        }

        // set ball location
        ball._x = x;
        ball._y = y;
    }

Although the “moveBall” function is long and complex, the “movePaddle” function couldn’t be any shorter. All it needs to do is set the vertical location of the paddle to the vertical location of the cursor.

<LINELENGTH>90</LINELENGTH>
function movePaddle() {
    // align paddle with cursor
    paddle._y = _ymouse;
}

Loose Ends

Be sure the ball movie clip instance is given the name “ball” and the paddle movie clip instance is given the name “paddle.” Also, if the walls are not exactly where they are in the example movie, then be sure to set the constants in the “initGame” function to match them.

The main game frame also needs a stop() on it so that the main timeline stops, although the “actions” movie clip will continue to loop and call functions.

Other Possibilities

One improvement that can be made to this game is to give players a certain number of balls that they can lose. Then, instead of the game ending as soon as the first ball is lost, it can continue.

You can do this by setting a variable, such as “ballNum,” to a particular number at the start of the game. Then, instead of going to a “game over” frame, you can go to a “ball lost” frame if “ballNum” is greater than 0. The player can press a button and play again, but with a “ballNum” of one less.

Paddle Ball

Paddle BallExample file: Paddleball.fla

Although the previous game is fun, it lacks a serious challenge. There is no real way to “win” the game. Instead, you play for as long as you can until you lose.

A more interesting game would allow the player to control one paddle, while the computer would control the other. The player tries not to let a ball get past and hopes the computer misses.

Figure 11.3 shows what the example movie, Paddleball.fla, looks like. The player controls the left paddle and the computer controls the right paddle.

In Paddle Ball, the player volleys back and forth with the computer.

Figure 11.3. In Paddle Ball, the player volleys back and forth with the computer.

Project Goal

The goal for this game is to create an artificially intelligent opponent for the player to compete against. The left paddle is to be controlled by the player, whereas the right paddle uses logic to try to mimic what a human opponent might do.

The ball bounces off the top and bottom of the screen, but it is up to the human player and the computer player to make sure it does not leave the screen from the sides.

When a ball gets past either player, the game pauses until the player hits a “serve” button. Then the ball launches itself from the middle of the screen. The game keeps score and ends when either player gets seven points.

Approach

There are many ways to make the artificial intelligence for this game. One would be to have the paddle follow the ball. This would be too perfect, however, because it would be impossible for the computer to miss.

A better way would be to have the computer’s paddle move slowly toward the position of the ball. If the ball is moving too fast, the computer might not be able to make it to the correct position quickly enough. Also, the paddle moves only when the ball is moving toward the computer’s side.

Tip

Tip

Artificial intelligence sounds mysterious and complex. For games, however, it isn’t so important that the opponent be smart. The computer opponent merely needs to facilitate fun game play. In many cases, like in this game, it would be easy to make an opponent that is flawless. However, that would make an impossible-to-win game that is no fun. The goal is to make an opponent that presents enough of a challenge so that the game is not easy, but not so much of a challenge that you can’t win.

Keeping score just requires a couple of variables. However, pausing the game between serves can be tricky, so the game needs two frames: one in which the program waits for the player to press the “serve” button, and one in which the game action takes place. This second frame starts by setting a random initial direction for the ball.

Preparing the Movie

This movie is basically the same as the previous one. Instead of three frames, you need four: a “start game” frame, a “start level” frame, a “play” frame, and a “game over” frame. The “start level” frame is seen before every ball is served. The “game over” frame is seen only after the last ball has been lost.

There needs to be one paddle movie clip named “paddle” (like in the previous game), and one named “computerPaddle.” This second paddle is controlled by your ActionScript. Because the computer paddle is on the right, the right wall needs to be removed. The top and bottom walls should stay.

Writing the Code

Starting with the previous movie, you need to make some changes to the existing functions, and add an important new function. Here is the “actions” movie clip script, which adds a call to this new function, “moveComputerPaddle”:

<LINELENGTH>90</LINELENGTH>
onClipEvent(load) {
    _root.startLevel();
}

onClipEvent(enterFrame) {
    _root.moveBall();
    _root.movePaddle();
    _root.moveComputerPaddle();
}

Instead of a “startGame” function, this game has a “startLevel” function that does all the same things as the preceding “startGame” function, but also sets the ball moving in a random direction. It does this by sending the ball up 50% of the time, down 50% of the time, as well as left 50% of the time and right 50% of the time. This gives you four possible diagonal directions.

<LINELENGTH>90</LINELENGTH>
function startLevel() {

    // get start position of the ball
    x = ball._x;
    y = ball._y;

    // set initial speed, one of four random diagonals
    dx = 5;
    dy = 5;
    if (Math.random() < .5) dx *= -1;
    if (Math.random() < .5) dy *= -1;

    // hide cursor
    Mouse.hide();

    // set constants

    rightWall = 550;
    leftWall = 0
    topWall = 0;
    bottomWall = 400;
    ballRadius = ball._width/2;
    passedPaddle = false;
}

The “moveBall” function now includes code to detect when the ball has passed the computer’s paddle on the right Writing the Code. This is similar to the code that handles the player’s paddle on the left Writing the Code, which is the same as in the preceding game.

When the ball is lost on either the left side Writing the Code or the right side Writing the Code, the game is usually sent back to the “start level” frame. However, if there are no more balls left, it is sent to the “game over” frame. Depending on who lost the ball, a point is awarded to either “computerScore” or “playerScore.”

<LINELENGTH>90</LINELENGTH>
   function moveBall() {
       // change x and y
       x += dx;
       y += dy;

       // check bottom
       if (y+ballRadius > bottomWall) {
           overshoot = (y+ballRadius) - bottomWall;
           y -= overShoot*2;
           dy *= -1;
       }

       // check top
       if (y-ballRadius < topWall) {
           overshoot = topWall - (y-ballRadius);
           y += overShoot*2;
           dy *= -1;
       }

Writing the Code   // is it where it should hit the paddle?
       paddleRight = paddle._x+(paddle._width/2);
       if ((x-ballRadius < paddleRight) and !passedPaddle) {

           // is the paddle there?
           paddleTop = paddle._y-(paddle._height/2);
           paddleBottom = paddle._y+(paddle._height/2);
           if ((y > paddleTop) and (y < paddleBottom)) {

               // hit paddle
               overshoot = paddleRight - (x-ballRadius);
               x += overShoot*2;
               dx *= -1;

               // speed up
               dx *= 1.05;
               dy *= 1.05;
           } else {

               // missed paddle, don't check again
               passedPaddle = true;
           }
       }

Writing the Code   // is it where it should hit the computer's paddle?
       paddleLeft = computerPaddle._x-(computerPaddle._width/2);
       if ((x+ballRadius > paddleLeft) and !passedPaddle) {

           // is the paddle there?
           paddleTop = computerPaddle._y-(computerPaddle._height/2);
           paddleBottom = computerPaddle._y+(computerPaddle._height/2);
           if ((y > paddleTop) and (y < paddleBottom)) {

               // hit paddle
               overshoot =  (x+ballRadius) - paddleLeft;
               x -= overShoot*2;
               dx *= -1;

               // speed up
               dx *= 1.05;
               dy *= 1.05;
           } else {

               // missed paddle, don't check again
               passedPaddle = true;
           }
       }

Writing the Code   // check left wall
       if ((x-ballRadius < leftWall) and passedPaddle) {
           Mouse.show();
           computerScore++;
           if (numBalls == 0) {
               gotoAndPlay("game over");
           } else {
               numBalls--;
               gotoAndPlay("start level");
           }
       }

Writing the Code   // check right wall
       if ((x+ballRadius > rightWall) and passedPaddle) {
           Mouse.show();
           playerScore++;
           if (numBalls == 0) {
               gotoAndPlay("game over");
           } else {
               numBalls--;
               gotoAndPlay("start level");
           }
       }

       // set ball location
       ball._x = x;
       ball._y = y;
   }

The “movePaddle” function is identical to the one in the preceding game. However, you need to add the “moveComputerPaddle” function that controls the right paddle. This function moves the paddle only if the ball is headed to the right. Then, it moves the paddle up if the ball is above the height of the paddle, and down if it is below.

The speed at which it moves is set at the start of the function. The higher you make this value, the longer the paddle will be able to keep up with the ball.

<LINELENGTH>90</LINELENGTH>
function moveComputerPaddle() {
    //  set speed of paddle
    moveAmount = 8;

    // see whether ball is moving in this direction
    if (dx > 0) {

        // move paddle up
        if (y < computerPaddle._y-moveAmount) {
            computerPaddle._y -= moveAmount;
        // move paddle down
        } else if (y > computerPaddle._y+moveAmount) {
            computerPaddle._y += moveAmount;
        }
    }
}

One additional piece of code that you need for this movie is something in the “start game” frame to initialize the number of balls and the score. This number can’t be put into the “startLevel” function because it should only be set at the start of the game, not before each ball is served.

<LINELENGTH>90</LINELENGTH>
numBalls = 7;
computerScore = 0;
playerScore = 0;
stop();

Loose Ends

You also need to create the “playerScore” and “computerScore” text areas and place them on the Stage. They have been placed in all but the “start game” frame so that they are visible between serves and at the end of the game.

Other Possibilities

It is easy to change the number of balls by just changing “numBalls” in the “start game” frame. However, you can also change other things about the game to make it longer or more difficult. You can increase the speed of the computer’s paddle by changing one value in the “moveComputerPaddle” function.

You can also make the computer smarter. For instance, you can write code to predict the destination of the ball and have the computer paddle move there rather than just follow the ball. The ball bounces off the top or bottom wall only once while crossing the screen, so this prediction can be done with just a bit of simple math if you are up for it.

Paddle Bricks

Paddle BricksExample file: Paddlebricks.fla

The next game uses the three primary elements of the previous two games—a ball, a paddle, and walls—to build a game far more advanced. This is another classic arcade game, first called Breakout, and then cloned under various names.

Figure 11.4 shows the example movie. In addition to a ball and paddle, you can see five rows of bricks at the top of the screen. The object of the game is to bounce the ball off these bricks, which makes them disappear. Get rid of all the bricks and the next level is even faster.

The “Paddle Bricks” game features rows of bricks that the player must hit with the ball.

Figure 11.4. The “Paddle Bricks” game features rows of bricks that the player must hit with the ball.

Project Goal

The goal is to build a classic paddle and brick arcade game. The paddle moves horizontally along with the mouse. The ball bounces off the top and sides, but is lost if it gets past the paddle on the bottom.

When a brick is hit by the ball, the ball bounces back, but the brick disappears. After all the bricks have been removed, the level ends. The next level has the same bricks, but a faster ball. If the player loses three balls, the game is over. Check out the movie, Paddlebricks.fla, to see how the game plays.

Another change from the previous ball and paddle games is that the direction of the ball is affected by where the ball hits the paddle. If the ball strikes the left side of the paddle, the ball goes left, if it hits the right side, it goes right. The angle is determined by how far from the center of the paddle the impact occurs.

Approach

The code to detect whether the ball hits the paddle or the walls is similar to the previous two games. One difference is to allow the ball to bounce back from the paddle at any point, not just the top side of the paddle. This makes it a little easier to hit the ball because the player can whack it with the side of the paddle.

When the ball intersects a brick, it reverses the vertical direction. The brick is repositioned off the screen.

Rather than use hitTest to determine when the ball hits a brick, you need to examine all four sides of the ball against all four sides of the brick. If the ball and brick overlap at all, it’s counted as a hit. With hitTest, you can only detect when the center of the ball is inside the rectangle of the brick. That’s not accurate enough for this game.

When the ball hits the paddle, you need to calculate the distance from the center of the ball to the center of the paddle. The paddle is 50 pixels long, so the distance can be a little more than 25 pixels, either positive or negative. Divide this number by 4 to get a value between about –7 and 7. This is used as the new value of “dx,” which will be the horizontal speed.

This means that the player can direct the ball. If the player hits the ball on the left corner, for instance, the ball is sent sharply to the left. If it is hit in the middle, it should go straight up.

Preparing the Movie

This movie requires five frames, more than any other game so far. The first frame is the “start game” frame. It appears only at the start of a brand new game. Pressing the “Play” button takes the player directly to the “play” frame and the game starts.

The second frame is the “start level” frame. It is shown when the player starts level 2, or any level after that. The “Play” button here also takes the player to the “play” frame in which the new level starts.

The third frame is the “start ball” frame. This frame is shown when the player loses a ball and needs to be served another one. Looking at the example movie, you can see that the bricks exist on both frames three and four, which is the “play” frame. This enables the brick movie clips to remain in place while the movie travels from the “play” frame to the “start ball” frame. Otherwise, the bricks would be reset to their original positions.

The last frame is the “game over” frame. Pressing the “Play” button on this frame takes you back to the “start game” frame where some important variables are reset.

In addition to the frame arrangement, the bricks for frames three and four need to be created. In the example movie, these are 48 pixels wide by 8 pixels high. They are spaced 50×10 pixels in the example movie, which makes 11 bricks across by 5 down for a total of 55 bricks.

Tip

Tip

To avoid having to name 55 bricks on the Stage, consider starting with no bricks on the Stage at all, and using attachMovie to add each brick with code. Although this technique is not used here, you can see it in action in the next game in this chapter.

Unfortunately, each brick must be individually named for the code to recognize it. They are named “a1” to “a55” in the example movie. The ball clip is named “ball” and the paddle clip is named “paddle.”

Writing the Code

Before the game frame is reached, two important variables need to be set in the “start game” frame of the movie. These represent the initial vertical speed of the ball and the number of balls to be served:

<LINELENGTH>90</LINELENGTH>
dy = 3;
numBalls = 3;
stop();

When the “play” frame is reached, the usual “actions” movie clip is used to trigger functions on a regular basis. In this game, all the wall and paddle collision detection has been placed in the “moveBall” function, but a separate function—”checkCollisions”—was made for the bricks.

<LINELENGTH>90</LINELENGTH>
onClipEvent(load) {
    _root.startBall();
}

onClipEvent(enterFrame) {
    _root.moveBall();
    _root.movePaddle();
    _root.checkCollisions();
}

When the “play” frame begins, the ball is served. The location of the ball is determined by where it happens to be sitting on the Stage before the code takes over. The horizontal speed of the ball is always 3 to the right. The vertical speed was set in the first frame, when “dy” was given a value of 3. However, this will be changed before the next level begins.

In addition to the ball settings, take this opportunity to set some values that will never change during the course of play:

<LINELENGTH>90</LINELENGTH>
function startBall() {
    // get starting point of ball
    x = ball._x;
    y = ball._y;

    // set starting x speed
    dx = 3;

    // hide cursor
    Mouse.hide();

    // set constants
    rightWall = 550;
    leftWall = 0
    topWall = 0;
    bottomWall = 400;
    ballRadius = ball._width/2;
    paddleTop = paddle._y-paddle._height/2;
    paddleBottom = paddle._y+paddle._height/2;
}

The next function controls the paddle by aligning it horizontally with the mouse:

<LINELENGTH>90</LINELENGTH>
// paddle follows cursor
function movePaddle() {
    paddle._x = _xmouse;
}

You will recognize the next function because it looks a lot like the “moveBall” function in the other games of this chapter. There are some differences, however.

To determine whether the ball hits the paddle, the code checks to see whether the sides of the ball and the sides of the paddle are overlapping at all Writing the Code. Then, when there is a hit, the horizontal speed of the ball is determined based on where the ball hit the paddle Writing the Code. In addition, the code to determine when the ball has been missed is simpler because it just checks to see whether the ball has passed the bottom Writing the Code.

<LINELENGTH>90</LINELENGTH>
    function moveBall() {
        // change x and y
        x += dx;
        y += dy;

        // check right
        if (x+ballRadius > rightWall) {
            overshoot = (x+ballRadius) - rightWall;
            x -= overShoot*2;
            dx *= -1;
        }

        // check left
        if (x-ballRadius < leftWall) {
            overshoot = leftWall - (x-ballRadius);
            x += overShoot*2;
            dx *= -1;
        }

        // check top
        if (y-ballRadius < topWall) {
            overshoot = topWall - (y-ballRadius);
            y += overShoot*2;
            dy *= -1;
        }
Writing the Code    // is it where it should hit the paddle?
        if ((y+ballRadius > paddleTop) and (y-ballRadius < paddleBottom)) {

            // is the paddle there?
            paddleLeft = paddle._x-(paddle._width/2);
            paddleRight = paddle._x+(paddle._width/2);
            if ((x+ballRadius > paddleLeft) and (x-ballRadius < paddleRight)) {

                // hit paddle
                overshoot = paddleTop - (y+ballRadius);
                y += overShoot*2;
                dy *= -1;

Writing the Code            // set horizontal speed of ball
                // depending on where the paddle
                // and ball connected
                dx = (ball._x - paddle._x)/4;

            } else {

                // missed paddle, don't check again
                passedPaddle = true;
            }
        }

        // check bottom
Writing the Code   if (y > bottomWall){
           Mouse.show();
           if (numBalls == 0) {

               // no more balls, game over
               gotoAndPlay("game over");
           } else {

               // one less ball
               numBalls--;
               gotoAndPlay("start ball");
           }
       }

       // set ball
       ball._x = x;
       ball._y = y;
    }

To determine whether the ball has hit a brick, the code loops through all 55 bricks. A brick at the horizontal location –1000 has already been hit, so it is ignored. Otherwise, the “brickHit” function is called to see whether a brick and the ball overlap. If they do, the brick is removed and the ball bounces.

Notice variable “leveldone.” It starts off as true, but is changed to false as soon as a brick is encountered that is in play and is not being hit by the ball. If the “leveldone” variable remains true after all balls have been hit, then the player has succeeded in removing all the bricks. The game now goes to the “start level” frame, but not before the vertical speed of the ball, “dy,” has been increased.

Tip

Tip

Notice that you must check to see whether the vertical speed of the ball is greater than 7, and set it back to 7 if it is. The bricks are all 8 pixels high. A speed of 8 or higher could cause the ball to skip over bricks without hitting them. Fortunately, a speed of 7 is fast enough that even a good player should not be able to keep up for long.

<LINELENGTH>90</LINELENGTH>
function checkCollisions() {
    // get sides of ball
    ballTop = ball._y - ball._height/2;
    ballBottom = ball._y + ball._height/2;
    ballLeft = ball._x - ball._width/2;
    ballRight = ball._x + ball._width/2;

    // assume level is done
    leveldone = true;

    // loop through bricks to see whether any were hit
    for(i=1;i<=55;i++) {
        brick = _root["a"+i];

        // see whether brick is still around
        if (brick._x <> -1000) {
            if (brickHit(brick)) {

                // brick hit, so take away
                brick._x = -1000;

                // reverse direction of ball
                dy *= -1;

            } else {

                // brick stays, so level is not over
                leveldone = false;
            }
        }
    }

    // see whether all bricks gone
    if (leveldone) {

        // start new level
        Mouse.show();
        gotoAndPlay("start level");

        // increase vertical speed
        dy += 1;
        if (dy > 7) dy = 7;
    }
}

The “hitBrick” function checks all four sides of the ball against all four sides of the brick to see whether there is any overlap. It returns a true or false.

Tip

Tip

Notice that the “hitBrick” function contains four nested if statements. You might wonder why a string of four tests with and between each one is not used. The reason is speed. With four nested if statements, Flash can find one of these conditions to be false and never have to check the others. This significantly reduces the amount of work that Flash has to do, and increases the speed of the game. With and operators, Flash would have to check all four conditions, even if the first one were false to begin with.

<LINELENGTH>90</LINELENGTH>
function brickHit(brick) {
    // perform tests on all four sides
    if (ballTop <= brick._y + brick._height/2) {
        if (ballBottom >= brick._y - brick._height/2) {
            if (ballRight >= brick._x - brick._width/2) {
                if (ballLeft <= brick._x + brick._width/2) {

                    // all four tests true, so brick is hit
                    return(true);
                }
            }
        }
    }

    // brick not hit
    return(false);
}

Loose Ends

A lot of elements need to be set perfectly for the code to work. Check out the example movie, Paddlebricks.fla, to see a working version of this game in action. To make your own version, you have to remember to name all the movie clips and place stop commands in each frame. You also need to remember the little pieces of code in the buttons and the first frame.

The rows of bricks were colored in using the “Tint” effect to make the game more visually interesting. The colors have nothing at all to do with the game’s functionality.

Other Possibilities

To make this a real game, you should add scoring. I didn’t want to further complicate the code in the example here. Just add a “score” text area and link it to the “score” variable. Then, add a point every time the player gets a brick.

You might also want to add text areas to tell players what level they are on and how many balls they have left. Sound effects would be a nice and easy addition too.

3D Paddle Bricks

3D Paddle BricksExample File: 3Dpaddlebricks.fla

So far in this chapter you’ve seen the ball move horizontally and vertically. What if the ball were to move in the third dimension: depth?

Figure 11.5 shows what this might look like. The paddle is a semi-transparent square in the “front” of the game. Four side walls lead to a back wall that is some distance “in” to the screen. The ball appears to shrink as it gets farther from the paddle. The object is to knock out all the bricks in the back wall.

The object of this game is familiar, but the perspective view adds a new twist.

Figure 11.5. The object of this game is familiar, but the perspective view adds a new twist.

Project Goal

The goal of this game is to create an illusion. Computer screens are hopelessly stuck in two dimensions. But by changing the size of the ball and using perspective lines to make the ball move toward the center of the screen as it gets farther away, you can create the illusion that the ball is moving into the screen.

The goal is to knock out all 16 bricks in the back wall. You do this by hitting each brick once. When the ball reaches the level of the paddle, the paddle must be in position to hit the ball. The spot on the paddle that is hit determines the new angle of the ball. When all 16 bricks have been removed, the level is over. The next level is the same, but the ball moves faster.

Approach

Three variables are necessary to keep track of the position of the ball. You can use “x” and “y” to keep track of the horizontal and vertical position of the ball. A third variable, “z,” keeps track of the depth of the ball—how far into the screen it is.

These three variables determine the ball’s position inside the imaginary box of the game. This box is 400 units in size horizontally, 400 vertically, and 140 deep. To translate this to screen coordinates is a little tricky. If you look at Figure 11.5 again, you can see that two box shapes are visible. The outer box, which shares a border with the whole screen, is at the level of the paddle. It is 400×400. The inner box, which represents the back wall, is 120×120.

Figure 11.6 shows these two boxes again, but this time marked with x, y, and z coordinates. The upper-left corner of both boxes has an x value of 0 and a y value of 0. However, the outer corner has a z value of 0 whereas the inner corner has a z value of 140. All the other corners are labeled as well.

The x, y, and z values of each corner of the game area are labeled.

Figure 11.6. The x, y, and z values of each corner of the game area are labeled.

If the ball is at x and y location 0,0 and moves from 0 to 140 z, then it follows the edge line shown in Figure 11.6. If the ball is at the center of the screen, at 200,200, and moves from 0 to 140 z, it does not appear to move left or right at all. If the ball is at an odd position, like 50,65, and moves from 0 to 140 z, then it must follow its own perspective line so that it appears in the same relative position at the front and back.

The other part of the illusion is to scale the size of the ball down as it moves farther away.

Preparing the Movie

The example movie includes four frames. The second one is where all the action takes place. The background on all frames is the box shown in Figure 11.5. The outer border is 400×400, filling the Stage. The inner border, representing the back of the box, is 120×120 and is at the exact center.

Three other movie clips are also on the screen. The first is the paddle, a 70×70 box named “paddle” and set to have an alpha value of 50% so that it is semi-transparent. The ball is a circle that is 30 units in diameter and is named “ball.” There is also an “action” movie clip off to the side.

In the Library, there is another movie clip named “brick.” This clip is set to export with the movie. It’s used to create the bricks that cover the back wall.

If you look closely at Figure 11.5, you can see that in addition to the thick lines of the inner and outer box, there is also a thin-lined box somewhere in the middle. This set of lines moves with the ball along the edges of the screen. It is there to help the player judge where the ball is located. Test the example movie to see how it works. You need a 400×400 box movie clip to make these lines. The instance name of this movie clip is “ring.”

Writing the Code

The code consists mostly of functions placed on the second frame. This first one initializes the game. Instead of individual variables to store the x, y and z values of the ball, we use a single variable object, “ballpos,” that has three properties. So, “ballpos.x” refers to the ball’s x position. We do the same for “ballvel,” which stores the x, y, and z speed of the ball.

The “ballpos” is set so that the ball starts at the center of the back wall. The “ballvel” is set so that the ball starts by coming straight back at the paddle at a speed equal to the game level plus one. So the game starts with the ball having a speed of 2.

The next portion of the “initGame” function creates 16 brick movie clips from the “brick” Library symbol. They are arranged to cover the back wall evenly.

Finally, “initGame” changes the depth of the ball and paddle to make sure that they appear in front of the bricks that were just created.

<LINELENGTH>90</LINELENGTH>
function initGame() {
    // set ball position
    ballpos = {x:200, y:200, z:140};

    // set ball speed
    ballvel = {x:0, y:0, z:-(1+gameLevel)};

    // create back wall bricks
    bricks = new Array();
    for(var x=0;x<4;x++) {
        for(var y=0;y<4;y++) {
            brick = attachMovie("brick","brick"+x+y,x+y*4);
            brick._x = 155+30*x;
            brick._y = 155+30*y;
            bricks.push(brick);
        }
    }

    // ball and paddle in front of bricks
    paddle.swapDepths(101);
    ball.swapDepths(100);
}

The job of the “actions” movie clip is to call two functions every frame.

<LINELENGTH>90</LINELENGTH>
onClipEvent(enterFrame) {
    _root.movePaddle();
    _root.moveBall();
}

The first of these functions, “movePaddle,” is very simple. It just keeps the paddle in line with the cursor.

<LINELENGTH>90</LINELENGTH>
function movePaddle() {
    // paddle position matches cursor
    paddle._x = _root._xmouse;
    paddle._y = _root._ymouse;
}

The “moveBall” function, on the other hand, does a lot of work. It starts by changing “ballpos” by “ballvel,” thus moving the ball one step Writing the Code.

Next, the ball position on the screen is calculated Writing the Code. The x position is determined by starting with “ballpos.x” and then adjusting it according to “ballpos.z.” The farther away the ball is, the more of an adjustment is made. The other part of the adjustment is determined by how far the ball is from the side. If a ball is 50% between the side and the center (ballpos.x equals 100 or –100), then ballpos.z times 50% is added or subtracted from the x screen location. If you are not quite sure about this calculation, try making up some “ballpos” values to see how they work out.

The next piece of code adjusts the scale of the ball according to the “ballpos.z” value Writing the Code. Because “ballpos.z” can go to only 140, then the minimum value for the scale is (200–140)/2, or 35%.

The next piece of the code moves the “ring” movie clip by setting its scale properties Writing the Code. The ring acts as a guide so players can tell how far back the ball is located. Many players may not even notice the ring, but their brains will be using it to help them win.

If the ball hits one of the sides of the 3D box Writing the Code, then the ball must reverse direction along that plane. All four walls are checked.

The back wall collision Writing the Code is a little more complex. The z direction is reversed. In addition, the brick movie clips are examined to see whether the ball hit any of them. A brick that is hit is removed and the player’s score is increased by 1.

There is no forward wall, but the user’s paddle is at that position instead. If the ball hits a z depth of 0, then the paddle is tested to see whether it is in the way Writing the Code. The paddle is 70×70, which means that the ball must be 35 pixels from the center of the paddle in x and y. If the ball hits the paddle, then the new x and y speed is decided by the distance from the collision to the center of the paddle Writing the Code. A hit in the exact center means that the ball moves straight ahead, whereas a hit on the left side sends the ball off to the left, and so on.

When the ball hits the paddle, the paddle’s _alpha property is increased for the current frame Writing the Code. It is then set back to its normal amount in the next frame Writing the Code. This temporary increase in intensity offers nice feedback to the user.

If the ball misses the paddle, the game is over Writing the Code. On the other hand, if all the bricks are gone Writing the Code, the level is complete.

<LINELENGTH>90</LINELENGTH>
    function moveBall() {
Writing the Code   // move ball in 3 dimensions
        ballpos.x += ballvel.x;
        ballpos.y += ballvel.y;
        ballpos.z += ballvel.z;

Writing the Code    // position ball on screen
        ball._x = ballpos.x + ballpos.z*(200-ballpos.x)/200;
        ball._y = ballpos.y + ballpos.z*(200-ballpos.y)/200;

Writing the Code    // adjust size of ball
        ball._xscale = (200-ballpos.z)/2;
        ball._yscale = (200-ballpos.z)/2;

Writing the Code    // adjust wall lines
        ring._xscale = (200-ballpos.z)/2;
        ring._yscale = (200-ballpos.z)/2;

Writing the Code    // check side collisions
        if (ballpos.x > 400) ballvel.x *= -1;
        if (ballpos.x < 0) ballvel.x *= -1;
        if (ballpos.y > 400) ballvel.y *= -1;
        if (ballpos.y < 0) ballvel.y *= -1;

Writing the Code    // back wall collisions
        if (ballpos.z > 140) {

            // reverse direction
            ballvel.z *= -1;

            // remove any bricks that have been hit
            for(var i=bricks.length-1;i>=0;i--) {
                if (bricks[i].hitTest(ball._x,ball._y)) {
                    bricks[i].removeMovieClip();
                    bricks.splice(i,1);
                    score++;
                }
            }
        }

Writing the Code    // paddle collision
        if (ballpos.z < 0) {

            // calc how close ball is to paddle
            px = ballpos.x-paddle._x;
            py = ballpos.y-paddle._y;

            // collision if within 35 pixels
            if ((Math.abs(px) < 35) and (Math.abs(py) < 35)) {

Writing the Code            // x and y speed according to distance from center
                ballvel.x = px/7;
                ballvel.y = py/7;

Writing the Code            // paddle brightens to show hit
                paddle._alpha = 90;
            } else {

Writing the Code            // missed ball
                removeBallAndPaddle();
                gotoAndStop("game over");
            }

            // reverse ball direction
            ballvel.z *= -1;

        } else {

Writing the Code        // return paddle to normal
            paddle._alpha = 50;
        }

Writing the Code    // see whether all bricks are gone
        if (bricks.length < 1) {
            gameLevel++;
            removeBallAndPaddle();
            gotoAndStop("level over");
        }

    }

Two more utility handlers are in the script. This first one removes the ball and paddle movie clips. If this is not done, they will hang around on the “level over” and “game over” frame.

<LINELENGTH>90</LINELENGTH>
function removeBallAndPaddle() {
    paddle.removeMovieClip();
    ball.removeMovieClip();
}

The “removeBricks” function removes all the bricks. It is used by the buttons on the “level over” and “game over” frames.

<LINELENGTH>90</LINELENGTH>
function removeBricks() {
    for(var i=0;i<bricks.length;i++) {
        bricks[i].removeMovieClip();
    }
}

The first frame of the movie, the “start” frame, sets the “gameLevel” to 1 and pauses the movie on that frame.

<LINELENGTH>90</LINELENGTH>
gameLevel = 1;
stop();

The button on that frame advances to the next frame.

<LINELENGTH>90</LINELENGTH>
on (press) {
    gotoAndStop("Play");
}

On the “play” frame are all the functions shown previously. In addition, a single command calls the “initGame” function to get things rolling.

When a level is complete, the game goes to the “level over” frame. The “actions” movie clip is not on this frame, so the ball stops moving automatically. When the user presses the button on this frame, the bricks are removed so that they can be replaced when the “initGame” function is called again.

<LINELENGTH>90</LINELENGTH>
on (press) {
    removeBricks();
    gotoAndStop("Play");
}

When the button on the “game over” frame is pressed, the bricks are also removed, but the movie goes to the “start” frame rather than back to “play.”

<LINELENGTH>90</LINELENGTH>
on (press) {
    removeBricks();
    gotoAndStop("Start");
}

Loose Ends

This game mostly fakes it as far as the 3D math goes. For instance, if the ball is to fly off the paddle at an angle, then the z speed of the ball should be changing so that the overall x, y, and z velocity is always the same. But these little shortcuts make for much simpler code while not compromising game play too much.

You will also probably want to hide the cursor at the start of the game with Mouse.hide(), just as you did in the other three games of this chapter. Remember to unhide it when the game is over with Mouse.show().

Other Possibilities

One easy change to this game is to place a picture behind the bricks on the back wall. This can be done without any ActionScript at all. When the bricks are removed, the picture is revealed. You can even place a movie clip with a different picture on each frame. Every time the level is increased, this movie clip advances one frame. So as players clear the bricks on each level, they get a new image. You can use this to tell a story, picture-by-picture. The player must advance through the levels to reveal the story.

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

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