Lessons.Flash.03

Flash Lesson 3:
Pong

Moving The Ball

The first step in creating a Pong game is getting the ball to move. We will be using ActionScript extensively to create this game as it is the code behind nearly everything that happens in a Flash game.

  • 1. Create a new Flash File (ActionScript 3.0)
  • 2. Name your layer "Objects"
  • 3. Create a square or circle in the center of the stage to represent the Pong ball
  • 4. Select the shape AND stroke (border)
  • 5. Press F8 to convert the selection to a symbol
  • 6. Choose "MovieClip" and name the symbol "mcBall"
  • 7. Select the object on the stage
  • 8. Change its instance name to "myBall"

What we did was create a class for the ball, which we can use as many times as we need to. While we will only use this class once, it is important to know that you can use it as many times as you want. The "mc" we put before "Ball" is short for MovieClip. The instance name is the name of the specific object on the stage. If you added another mcBall to the stage it would need to have a different instance name.

  • 9. Create a new layer called "Code"
  • 10. Open the Actions Panel on the Code Layer by pressing F9
  • 11. Add the following code to the Code Layer:

addEventListener(Event.ENTER_FRAME, BallMove);

function BallMove(event:Event)
{
    myBall.x = myBall.x + 5;
}

You can test your game by pressing "Ctrl-Enter." The ball should move to the right. The code above changes the x-coordinate of the ball by adding 5 to it. It does this by using an Event Listener which listens for Flash to enter the frame. Since we are always on frame 1 the Event Listener is always running. What it does is call the BallMove function where the ball is moved.

Movement on the Stage

By default, the stage in Flash is 550 pixels wide by 400 pixels tall. It is important to know that the origin, or (0, 0) point, is located in the upper-left of the stage. Moving down the stage causes the y-coordinate to get bigger while moving to the right will cause the x-coordinate to get bigger.

The Stage

  • 12. Modify your code to the following. The differences are in red.

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;


function BallMove(event:Event)
{
   myBall.x = myBall.x + x_speed;
   myBall.y = myBall.y + y_speed;
}

The ball moved to the right because Flash substituted “x_speed” for “5” in the movement code. Try changing “5” to something else and notice how the ball changes direction and speed. The word "var" means you are declaring a variable with the name "x_speed."

Next, we will cause the ball to bounce off the bottom and right sides of the stage. Later, we will learn a better way to do this, but for now we will simply test to see if the ball has gone past a certain point on the stage.

  • 13. Modify your code to the following. The differences are in red.

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;

function BallMove(event:Event)
{
   myBall.x = myBall.x + x_speed;
   myBall.y = myBall.y + y_speed;

   if (myBall.x > 525)
   {
      x_speed = -x_speed;
   }
   if (myBall.y > 375)
   {
      y_speed = -y_speed;
   }

}

The only thing we changed from the previous example is the addition of the if statements. If the ball’s X position is greater than 525 pixels, change “x_speed”. Now the next time the code executes, "x_speed" is negative and the ball will move -5 pixels, which is 5 pixels to the left. It now appears that the ball bounces when it hits the right side of the stage. The ball will also bounce off the bottom.

  • 14. Modify your code with the additions below:

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;

function BallMove(event:Event)
{
   myBall.x = myBall.x + x_speed;
   myBall.y = myBall.y + y_speed;

   if (myBall.x > 525 || myBall.x < 0)
   {
      x_speed = -x_speed;
   }
   if (myBall.y > 375 || myBall.y < 0)
   {
      y_speed = -y_speed;
   }
}

The last thing we will do is shorten our code a little bit.

  • 15. Modify your code with the changes in red below:

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;

function BallMove(event:Event)
{
   myBall.x += x_speed;
   myBall.y += y_speed;

   if (myBall.x > 525 || myBall.x < 0)
   {
      x_speed = -x_speed;
   }
   if (myBall.y > 375 || myBall.y < 0)
   {
      y_speed = -y_speed;
   }
}

Why did we need to write “myBall.x” twice? Lucky for us, most programming languages have a special operator for this kind of shortcut which not only sets a variable (using the "=" sign) but also performs a math operation on it (such as addition). This is exactly what we are trying to do (“+ x_speed” in our case). The shortcut we can use to do the exact same thing is the += operator. This operator says: take the variable and add something to it. There are also other operators, -=, *=, and /= which perform the other shortcut math operations. We can use one of these to simplify the code that changes the ball’s direction, “x_speed = -x_speed”. Instead, we can use the *= operator to set “x_speed” to itself multiplied by -1. Wouldn't this do the same thing as just changing the sign on the x_speed?

  • 16. Modify your code with the changes in red below:

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;

function BallMove(event:Event)
{
   myBall.x += x_speed;
   myBall.y += y_speed;

   if (myBall.x > 525 || myBall.x < 0)
   {
      x_speed *= -1;
   }
   if (myBall.y > 375 || myBall.y < 0)
   {
      y_speed *= -1;
   }
}

Pong Design

It is now time to begin to design our game. You will need to add the following to your game:

  • The Ball: We already made this.
  • Left Paddle: This paddle will use controls on the left side of the keyboard.
  • Right Paddle: This paddle will use controls on the right side of the keyboard.
  • Top Wall: This wall makes the ball bounce down (change Y-position).
  • Bottom Wall: This wall makes the ball bounce up (change Y-position).
  • Left Wall: This wall will be used for scoring and resetting the ball. If the ball comes in contact with this wall a point is scored for the right paddle.
  • Right Wall: This wall will be used for scoring and resetting the ball. If the ball comes in contact with this wall a point is scored for the left paddle.
  • 17. Make sure you are on the Objects Layer
  • 18. Create a MovieClip for each of the items above
  • 19. Name your MovieClips: "mcPaddleLeft", "mcPaddleRight", "mcTopWall", "mcBottomWall", "mcLeftWall", and "mcRightWall" and give them instance names that start with "my."

Pong

Collision Detection

The last change to our Pong game is also the most important: the function called hitTestObject(). hitTestObject checks for collisions, and Pong is a game all about collisions. The ball hitting the paddle, the ball hitting a wall, the ball crossing the goal, the paddle hitting the top wall; all of these are examples of collisions and all of these will require the use of hitTestObject() for our Pong game to work.

  • 21. Modify your code with the changes below:
  • 22. Move the ball so it will hit the different objects.
  • 23. Test your game to make sure the collision detection works for everything except the goals.
  • 24. Move the ball back to the middle.

addEventListener(Event.ENTER_FRAME, BallMove);

var x_speed = 5;
var y_speed = 5;

function BallMove(event:Event)
{
   myBall.x += x_speed;
   myBall.y += y_speed;

   if (myBall.hitTestObject(myPaddleLeft) || myBall.hitTestObject(myPaddleRight))
   {
      x_speed *= -1;
   }
   if (myBall.hitTestObject(myTopWall) || myBall.hitTestObject(myBottomWall))
   {
      y_speed *= -1;
   }
}

In the code above we put hitTestObject() in our if statements. Every hitTestObject() should always be inside of an if statement because it is a condition to check whether or not something has happened. For the condition of the if statement we started the hitTestObject() by first referencing the top ball by typing “myBall” and then calling the hitTestObject function. We need another MovieClip to check to see if a collision has happened so I checked to see if the left paddle and the ball collided. We did the same thing for the other paddle and the top and bottom walls. Since the game behaves differently when the ball hits one of the goals we will need to do that later. For now, we need to get the paddles moving.

Keyboard Movement

Now we have working walls and our paddles function correctly, but they don’t move! To use the keyboard to control MovieClips in Flash, we have to use an Event Listener for keyboard events. We will actually need TWO Event Listeners: one which checks to see if a key is currently being held down called KEY_DOWN and another that checks to see if a key has been let go called KEY_UP. We will use variables to see if keys are currently being pressed to allow both paddles to move at the same time.

  • 25. Modify your code so with the changes below:

addEventListener(Event.ENTER_FRAME, BallMove);
stage.addEventListener(KeyboardEvent.KEY_DOWN, PaddleMove);
stage.addEventListener(KeyboardEvent.KEY_UP, PaddleStop);


var x_speed = 5;
var y_speed = 5;
var paddle_speed = 10;

var leftPadUp = false;
var leftPadDown = false;
var rightPadUp = false;
var rightPadDown = false;


function BallMove(event:Event)
{
   myBall.x += x_speed;
   myBall.y += y_speed;

   if (myBall.hitTestObject(myPaddleLeft) || myBall.hitTestObject(myPaddleRight))
   {
      x_speed *= -1;
   }
   if (myBall.hitTestObject(myTopWall) || myBall.hitTestObject(myBottomWall))
   {
      y_speed *= -1;
   }
}

Note that these two addEventListener functions have “stage.” in front of them. This is because we check for keyboard events on the stage and not from the timeline, which is where our code is currently running from. The paddle_speed variable will be a speed for the paddles, and the other four variables are Boolean variables that store false if a paddle is not moving in that direction and true if it should be moving in that direction. Now we need to create the two functions to move or stop the paddles. We will also move our collision detection into a new function and make an event listener for it. We will also rename the BallMove function since it now moves the paddles as well.

  • 26. Modify your code with the changes in red below:

addEventListener(Event.ENTER_FRAME, Move);
addEventListener(Event.ENTER_FRAME, Collision);
stage.addEventListener(KeyboardEvent.KEY_DOWN, PaddleMove);
stage.addEventListener(KeyboardEvent.KEY_UP, PaddleStop);

var x_speed = 5;
var y_speed = 5;
var paddle_speed = 10;

var leftPadUp = false;
var leftPadDown = false;
var rightPadUp = false;
var rightPadDown = false;

function Move(event:Event)
{
   myBall.x += x_speed;
   myBall.y += y_speed;

   if(leftPadUp == true && myPaddleLeft.hitTestObject(myTopWall) == false)
   {
      myPaddleLeft.y -= paddle_speed;
   }
   if(rightPadUp == true && myPaddleRight.hitTestObject(myTopWall) == false)
   {
      myPaddleRight.y -= paddle_speed;
   }
   if(leftPadDown == true && myPaddleLeft.hitTestObject(myBottomWall) == false)
   {
      myPaddleLeft.y += paddle_speed;
   }
   if(rightPadDown == true && myPaddleRight.hitTestObject(myBottomWall) == false)
   {
      myPaddleRight.y += paddle_speed;
   }

}

function Collision(event:Event)
{
   if(myBall.hitTestObject(myTopWall) || myBall.hitTestObject(myBottomWall))
   {
      y_speed *= -1;
   }
   if(myBall.hitTestObject(myPaddleLeft) || myBall.hitTestObject(myPaddleRight))
   {
      x_speed *= -1;
   }
}


function PaddleMove(event:KeyboardEvent)
{
   if(event.keyCode == Keyboard.UP)
   {
      rightPadUp = true;
   }
   if(event.keyCode == 65)
   {
      leftPadUp = true;
   }
   if(event.keyCode == Keyboard.DOWN)
   {
      rightPadDown = true;
   }
   if(event.keyCode == 90)
   {
      leftPadDown = true;
   }
}


function PaddleStop(event:KeyboardEvent)
{
   if(event.keyCode == Keyboard.UP)
   {
      rightPadUp = false;
   }
   if(event.keyCode == 65)
   {
      leftPadUp = false;
   }
   if(event.keyCode == Keyboard.DOWN)
   {
      rightPadDown = false;
   }
   if(event.keyCode == 90)
   {
      leftPadDown = false;
   }
}

event.KeyCode checks the keyboard event for the code that represents the key that was pressed or let go. Keyboard.UP and Keyboard.DOWN store the code for the Up and Down keys, but there is no function for getting the letter keys on the keyboard. You can search the web for Actionscript Key Codes to find the numbers that represent other keys, or you can use 65 for “A” and 90 for “Z” as in the example. If you test your game you may notice the letter keys do not work. This is because the letters are causing shortcuts to activate in Flash. This won't happen in your final game, but you can disable keyboard shortcuts by going to Control>Disable Keyboard Shortcuts while previewing your movie.

Scoring Goals

The current status of the Pong game we have made is that the paddles work and the ball bounces off the top and bottom walls as well as each paddle. The only elements left we need to program are the left and right walls.

The left and right walls are special. They will be used for scoring. Let’s go over what needs to happen once a ball hits a left or right wall.

1. The player opposite of the wall gets a point.
2. The ball should be moved to the middle of the stage.

  • 27. Add the following event listener to the top of your code with the other event listeners:

addEventListener(Event.ENTER_FRAME, Goal);

  • 28. Now add the Goal function to the bottom of your code:

function Goal(event:Event)
{
   if(myBall.hitTestObject(myLeftWall))
   {
      myBall.x = 250;
      myBall.y = 200;
   }
   else if(myBall.hitTestObject(myRightWall))
   {
      myBall.x = 250;
      myBall.y = 200;
   }
}

To keep score we need to create two variables that will keep track of the score for each player.

  • 29. Add the following lines of code to the top of your code and to the Goal function. The periods are there so all of the code does not need to be written again.

.
.
.
var rightPadDown = false;

var p1Score = 0;
var p2Score = 0;

.
.
.
function Goal(event:Event)
{
   if(myBall.hitTestObject(myLeftWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p2Score++;
   }
   else if(myBall.hitTestObject(myRightWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p1Score++;
   }
}

Our game now keeps score in the code, but the score is not displayed anywhere on the stage. For that to happen we need to create a dynamic text box.

Dynamic Text

  • 30. Use the Text Tool to draw a text box
  • 31. Put a "0" in the text box
  • 32. In the Properties Pane change the type from "Static Text" to "Dynamic Text"
  • 33. Change the Instance Name of the text box to txtPlayer1
  • 34. Move the text box to the top-left corner
  • 35. Create a dynamic text box for player 2 and call it txtPlayer2

Since we gave an instance name to both text boxes we can access them from our Actionscript code just like a MovieClip.

  • 36. Modify the Goal function with the following additions:

.
.
.
function Goal(event:Event)
{
   if(myBall.hitTestObject(myLeftWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p2Score++;
      txtPlayer2.text = p2Score;
   }
   else if(myBall.hitTestObject(myRightWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p1Score++;
      txtPlayer1.text = p1Score;
   }
}

The Text Property of a text box is the text that is stored in the text box. We are simply replacing the text with the players score in the two new lines above.

Intro and Ending Screens

So far, we haven’t done anything with the main timeline. Your game still only uses one frame. If you want a title screen when you start the Pong game, follow these steps:

  • 37. Click on the keyframe on the Code Layer
  • 38. Click-and-drag the keyframe to Frame 10
  • 39. Do the same to the Objects Layer
  • 40. Go to the Properties Pane and change the Frame Label to "game"

Moving Frames

You should now have a blank keyframe on Frame 1 which you can add a title screen to. If you test your game right now, it will not work because when the movie starts it will play right through the first frame and it will not stop on the keyframe that contains the game.We will need to come up with a solution for this problem.

  • 41. Design the intro screen in Frame 1
  • 42. Click on the Code Layer of Frame 1
  • 43. Open the Actions Panel and add the following code:

stop();

stage.addEventListener(KeyboardEvent.KEY_DOWN, Start);

function Start(event:KeyboardEvent)
{
   if(event.keyCode == Keyboard.SPACE)
   {
      gotoAndStop("game");
   }
}

The code above stops code execution as soon as the Flash file begins. An event listener listens for a key down and if the Spacebar is pressed it goes to the game frame.

The final step in our game is to create winning screens for the two players. This will work similarly to our intro screen except we only want to go to these screens when a player scores 10 goals. We will need to remove all event listeners when the game ends so we do not run into strange errors.

  • 44. Create keyframes on two different frames
  • 45. Design the winning screens for each player
  • 46. Label the frames p1Wins and p2Wins
  • 47. Modify the code in the Goal function:

.
.
.
function Goal(event:Event)
{
   if(myBall.hitTestObject(myLeftWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p2Score++;
      txtPlayer2.text = p2Score;
      if (p2Score == 10)
      {
         removeEventListener(Event.ENTER_FRAME, Move);
         removeEventListener(Event.ENTER_FRAME, Collision);
         removeEventListener(Event.ENTER_FRAME, Goal);
         stage.removeEventListener(KeyboardEvent.KEY_DOWN, PaddleMove);
         stage.removeEventListener(KeyboardEvent.KEY_UP, PaddleStop);
         gotoAndStop("p2Wins");
      }

   }
   else if(myBall.hitTestObject(myRightWall))
   {
      myBall.x = 250;
      myBall.y = 200;
      p1Score++;
      txtPlayer1.text = p1Score;
      if (p1Score == 10)
      {
         removeEventListener(Event.ENTER_FRAME, Move);
         removeEventListener(Event.ENTER_FRAME, Collision);
         removeEventListener(Event.ENTER_FRAME, Goal);
         stage.removeEventListener(KeyboardEvent.KEY_DOWN, PaddleMove);
         stage.removeEventListener(KeyboardEvent.KEY_UP, PaddleStop);
         gotoAndStop("p1Wins");
      }

   }
}

Your Pong game should now be complete!