IE179 Project 2

Flash Game Tutorial 4



In this tutorial you'll put together a simple but full featured game. You've already performed most of the steps in previous tutorials. If you feel comfortable with actionScript and Flash, you can skim this tutorial for new material. If not, you should proceed step by step.

  1. Create a new game:
    1. Open Flash
    2. Select File->Save As
    3. In the Save As window select Desktop from lefthand panel, change the file name to MyGame.fla then click Save.
  2. Create three additional layers for the game. Rename the layers (from the top) lLabels, lScripts, and lPlayer and lScene. (To keep our various names straight we'll use prefix letters; here layer names are prefixed with the letter l.) Select the lScripts layer and open the actionScript panel. Add the following script:
    //Main Game Script
    
    Any acript you add in this tutorial should be added here unless you are explicitly told otherwise.
  3. Create a dummy movie clip for the scene:
    1. Select Insert->NewSymbol.
    2. In the new symbol window select Movie Clip, change the name to mScene, then click OK. (We prefix movie clip symbols with an m.)
    3. Return to the stage for Scene 1.
    4. Drag the icon for mScene onto the stage.
    5. In the Properties panel name the movie clip instance imScene and set its X and Y coordinates to 0. (Instances of movie clip symbols are named with a prefixed with an im.)
    We are going to dynamically attach the background, platforms, etc. for our level to this empty clip.
  4. Create and export the background image.
    1. Download the image file background0.JPG to your desktop.
    2. In Flash, select Insert->New Symbol.
    3. In the new symbol window select Movie Clip, change the name to mBackground0 and click OK.
    4. You should now be on mBackground0 stage. Select File->Import and import your background image to the stage.
    5. In the Properties window set the X and Y coordinates to 0.
    6. In the Library window right-click on mBackground0 and select Linkages...
    7. Check the box labeled Export for Action Script then clickOK.
    8. Return to the stage for Scene 1.
  5. Create the XML file: Copy the following to a text file called level0.xml stored on the desktop.
    <level backgroundClip="mBackground0">
    </level>
    
  6. Add the following code to the actionScript.
    // initialization code
    theLevel = new XML();
    theLevel.ignoreWhite=true;
    theLevel.onLoad=parseLevel;
    theLevel.load("level0.xml");
    
    function parseLevel() {
    	trace("Read level description.");
    	var p=theLevel.childNodes[0];
    	
    	// set up background
    	imScene.attachMovie(p.attributes.backgroundClip,"i"+p.attributes.backgroundClip,0);
    
    }
    
    Run the game. It should load the background image.
  7. One problem with the background is that it is too small. One way to fix this is to edit the background symbol, mBackground0, and change its width to 1200 and its height to 400. Try this and run the game. The background is now the right size but it looks blocky. To avoid this problem, you should create the background image to be the proper size for the game! (Don't bother doing this for the tutorial but do bother on your real game.)
  8. Another problem with the background is that it runs off the right hand side of the screen. (If this isn't obvious maximize the game window.) To fix this problem we're going to add a stage mask.
    1. Select the lScene layer of Scene 1.
    2. Adjust the zoom to 25% so you can see the entire white area of the stage.
    3. Create a rectangle that exactly covers the white area.
    4. Select the rectangle and its border then right click and choose Convert to symbol. In the new symbol window select Movie Clip and name the symbol mMask.
    5. In the Properties window, name the instance of this symbol on the stage imMask.
    6. Add the following lines in the initalization code of the actionScript:
      imMask._visible = false;
      imScene.setMask(imMask);
      
      The first prevents the rectangle from being drawn. The second line prevents portions of imScene that lie outside the rectangle from being drawn.
    7. Run the game. The background should now fill the stage but not run off the right hand side.
  9. Add the player's character:
    1. Create a new movie clip symbol called mPC containing a circle with x and y coordinates of 0 and width and height of 50.
    2. Drag the icon for mPC onto the lPlayer layer of Scene 1. Name the instance imPC.
    3. The inital position of the player's character depends on the level information. Modify the first line of level0.xml as follows:
      <level backgroundClip="mBackground0" xStart="225" yStart="155">
      
    4. Add the following code to the parseLevel function after the background setup code.
      // set up the player's character(pc)
      	imPC._x=Number(p.attributes.xStart);
      	imPC._y=Number(p.attributes.yStart);
      
    5. Run the game. The circle should appear on the horizon.
  10. Allow the player to control the velocity of the character:
    1. The initial velocity of the player's character will be 0. Add the following lines at the top of the actionScript.
      //Global variables
      var xVelocity=0;		// pc's x velocity
      var yVelocity=0;		// pc's y velocity
      var acceleration=2;		// pc's acceleration due to arrow key
      
    2. Add the following functions to the end of the actionScript.
      //functions
      onEnterFrame=function () {
      
      	checkInput();
      	imScene._x -= xVelocity;
      	imScene._y -= yVelocity;
      	
      }
      
      function checkInput() {
      	if(Key.isDown(Key.RIGHT)) {
      		xVelocity += acceleration;
      		}
      
      	if (Key.isDown(Key.LEFT)) {
      		xVelocity -= acceleration;
      	}
      	
      	if (Key.isDown(Key.UP)) {
      		yVelocity -= acceleration;
      	}
      	
      	if (Key.isDown(Key.DOWN)) {
      		yVelocity += acceleration;
      	}
      }
      
    3. Run the game. You should be able to move the circle (or actually the background).
  11. Add platforms.
    1. Create and export a movie clip symbol called mPlatform consisting of a 100x100 filled rectangle.
    2. Add the following to level0.xml between the first line (i.e. <level ... >) and the last line (i.e. </level>):
      <platforms>
      <platform x="0" y="208" w="1200" h="196" v="false" clip="mPlatform"></platform>
      <platform x="150" y="100" w="100" h="40" v="true" clip="mPlatform"></platform>
      <platform x="500" y="120" w="100" h="40" v="true" clip="mPlatform"></platform>
      </platforms>
      
    3. In the variables section at the top of the actionScript add the following lines:
      var depth=1;		//  display depth for platforms;  starts at 1
      var platforms = new Array();  // platform data
      
    4. After the character setup code in the parseLevel function add the following lines:
      // set up the platforms
      	var q=p.childNodes[0];
      	parsePlatforms(q);	
      
    5. At the end of the actionScript add the following two function:
      function Platform(x,y,w,h,v,clip,clipName) {
      	this._x = x;
      	this._y = y;
      	this._width = w;
      	this._height = h;
      	this._visible = v;
      	this._clip = clip;
      	this._clipName = clipName
      }
      
      
      function parsePlatforms(p) {
      	numPlatforms=p.childNodes.length;
      	for (var i=0;i<numPlatforms;i++) {	
      		platforms[i] = new Platform(
      				Number(p.childNodes[i].attributes.x),
      				Number(p.childNodes[i].attributes.y),
      				Number(p.childNodes[i].attributes.w),
      				Number(p.childNodes[i].attributes.h),
      				Boolean(p.childNodes[i].attributes.v=="true"),
      				p.childNodes[i].attributes.clip,
      				"i"+p.childNodes[i].attributes.clip+i);
      		theClip = imScene.attachMovie(platforms[i]._clip,platforms[i]._name,depth);
      		depth++;
      		theClip._x = platforms[i]._x;
      		theClip._y = platforms[i]._y;
      		theClip._height = platforms[i]._height;
      		theClip._width = platforms[i]._width;
      		theClip._visible = platforms[i]._visible;
      	}
      }
      
    6. Run the game. You should see two platforms in the scene. Further, they should move with the background when you hit the arrow keys. Note, the xml file contains the description of a three platform but but the first has its visibility is set to false (v="false"). Change the visibility to true and rerun the game. The purpose of this platform will be clear in the next section. For now, change the visibility back to false.
  12. Add collision detection: Each time we move the character we must check if the movement will cause a collision. If a collision will occur, we move the character to the point of the collision and adjust its velocity.
      We'll use the xChange and yChange variables to store the change in the characters position. We'll also use a damping variable to reduce the velocity when a collision occurs. We'll also use (in the next section) a state variable onSurface. Copy the following lines to the variable section of your actionScript.
      var xChange;
      var yChange;
      var damp=.8
      var onSurface = true;
      var epsilon=.1
      
    1. Replace your onEnterFrame function with the following.
      onEnterFrame=function () {
      	checkInput();
      	platformDetect();
      	imScene._x -= xChange;
      	imScene._y -= yChange;	
      }
      
    2. The platformDetect function tests for collisions. This function works as described in class. Add this function at the end of your actionScript.
      function platformDetect() {
      	// initialize change to the velocities
      	xChange = xVelocity;
      	yChange = yVelocity;
      	
      	// if the player's character isn't moving there is not
      	// going to be a collision
      	if (xVelocity==0 && yVelocity==0)
      		return false;
      
      	// otherwise we have to check for collision
      	var pTop, pBottom, pLeft, pRight;  // platform positions
      	var cTopStart, cBottomStart, cLeftStart, cRightStart; // character positions at start
      	var cTopEnd, cBottomEnd, cLeftEnd, cRightEnd; // character positions at end
      	
      	// get boundaries of player's character before move
      	cTopStart = imPC._y;
      	cBottomStart = cTopStart + imPC._height;
      	cLeftStart = imPC._x;
      	cRightStart = cLeftStart + imPC._width;
      	
      	// get boundaries of player's character after move
      	cTopEnd = cTopStart + yVelocity;
      	cBottomEnd = cBottomStart + yVelocity;
      	cLeftEnd = cLeftStart + xVelocity;
      	cRightEnd = cRightStart + xVelocity; 
      
      	// assume not on surface
      	onSurface=false;
      	// test against each platform
      	for (i=0;i<platforms.length;i++) {
      
      		// get platform boundaries in screen coordinates
      		pTop = platforms[i]._y + imScene._y;
      		pBottom = platforms[i]._y + imScene._y + platforms[i]._height;
      		pLeft = platforms[i]._x + imScene._x;
      		pRight = platforms[i]._x + imScene._x + platforms[i]._width;
      				
      		// check if we've collided with the platform
      		if ((cBottomEnd ≥ pTop) && (cTopEnd ≤ pBottom) && (cRightEnd ≥ pLeft) && (cLeftEnd ≤ pRight)) {
      			
      			// we do collide when we move
      			// now find which side of the platform we hit
      
      			// check top
      			// did we start out above and move down?
      			// because of numerical inaccuracies we need
      			// an epsilon tolerance in our test so we don't 
      			//fall through platforms
      			if (cBottomStart ≤ pTop+epsilon) {
      				onSurface=true;
      				yChange=pTop-cBottomStart;
      				if (yVelocity >0) {
      					trace("collided with top of platform ");
      					var fraction=(pTop-cBottomStart)/yVelocity;
      					xChange=xVelocity*fraction;
      					// if we are making very small bounces
      					// stop the ball
      				
      					if (yVelocity < 0.9) {
      						yVelocity=0;
      					}
      					yVelocity *= - damp *.75;
      					
      					
      				}
      			}
      			
      			// check bottom
      			// did we start out below and move up?
      			else if (cTopStart ≥ pBottom && yVelocity  <  0) {
      				var fraction=(pBottom-cTopStart)/yVelocity;
      				xChange=xVelocity*fraction;
      				yChange=pBottom-cTopStart;
      				yVelocity *= - damp;
      				trace("collided with bottom of platform");
      			} 
      			
      			// check left of platform
      			// did we start to the left and move right
      			if (cRightStart ≤ pLeft && xVelocity  > 0) {
      				var fraction=(cRightStart-pLeft)/xVelocity;
      				xChange = cRightStart-pLeft;
      				if (!onSurface) {
      					yChange = fraction*yVelocity;
      				}
      				xVelocity *= - damp;
      				trace("collided with left of platform");
      			}
      
      			// check right of platform
      			// did we start to the right and move left
      			else if (cLeftStart ≥ pRight && xVelocity < 0) {
      				var fraction=(cLeftStart-pRight)/xVelocity;
      				xChange = pRight-cLeftStart;
      				if (!onSurface) {
      					yChange = fraction * yVelocity;
      				}
      				xVelocity *= - damp;
      				trace("collided with right of platform");
      			}
      		} // end of if 
      
      	} // end of for
      }
      
      
    3. Run the game. The ball will bounce off of the platforms. A message will print when there is a collision. Note, you can also add animations to let the ball squash when a collision occurs.
  13. Add gravity and friction:
      We want to add gravity when we are not on a horizontal surface and friction when we are on such a surface. Add the following lines in the variable section of the actionScript:
      var gravity = .5;
      var friction = .95;
      
      Add the following code in the onEnterFrame function after checkInput and before detectPlatform.
      if (onSurface) {
      		// add friction
      		xVelocity *= friction;
      		if (Math.abs(xVelocity)<.2) {
      			xVelocity = 0;
      		}
      	}
      	else {
      		yVelocity += gravity;
      	}
      
    Run the game. The ball should move nicely bouncing off of the horizon and the platforms. Remember that the collision algorithm is checking for collisions between the platforms and the bounding box of the ball. It is fairly easy to improve the collision so it uses a bounding circle instead of box. We leave that to try.
  14. Still to come: the splash screen, buttons, and changing levels.