Collision Detection

4 12 2008

Whether it’s a shooting game, a car racing, a pin ball, or a pac man game, collision detection is one of the most important aspects in building games. Without proper colision detection none of these games can exist in Flash. I want to share a very basic collision detection using a ball bounce example. Below, see how the ball bounces back when it hits any of the side walls or the moving wall in the center.

BallBounce.swf

BallBounce in Flash AS3 using hitTestObject()

BallBounce in Flash AS3 using hitTestObject()

Here, collision is detected using two AS3.0 techniques:

1. movieclip1.hitTestObject(movieClip2)
2. checking the overlapping of x and y coordinates of the two movieclips

I have also used a custom event (BounceEvent) that helps in announcing when the ball hits a wall and specifically which wall(or which side.)

There are 5 classes being used in this example:

1. Ball: A ball that will move and bounce around.
2. MovingWall: A movieclip in the center that is constantly moving to create obstruction for the ball.
3. Splat: A movieclip object to show the collision effect.
4. BounceEvent: A custom event to announce that a ball has hit the wall.
5. main: This is the document class. Initiates all the objects and controls the collision detection.

Ball.as

package
{
	import flash.display.MovieClip;
	public class Ball extends MovieClip
	{
		public function Ball(xPos:Number, yPos:Number)
		{

			var b:MovieClip = new MovieClip();
			b.graphics.beginFill(0xFF9933);
			b.graphics.drawCircle(0, 0, 10);
			x = xPos;
			y = yPos;
			addChild(b);
		}
	}
}

Splat.as

package
{
	import flash.display.MovieClip;
	import fl.transitions.Tween;
	import fl.transitions.easing.*;
	public class Splat extends MovieClip
	{
		public function Splat()
		{
			alpha = 0;
		}

		public function explode(xPos:Number, yPos:Number):void
		{
			x = xPos;
			y = yPos;

			new Tween(this, "alpha", Strong.easeOut, 30, 0, 0.2, true);
		}
	}
}

MovingWall.as

package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	public class MovingWall extends MovieClip
	{
		private var wallVelocityY:Number = 3;
		public function MovingWall(xPos:Number, yPos:Number)
		{
			x = 130;
			y = 40;
			setMotion();
		}
		private function setMotion():void
		{
			addEventListener(Event.ENTER_FRAME, moveWall);
		}
		private function moveWall(event:Event):void
		{
			y += wallVelocityY;
			if (y <= 40)
			{
				wallVelocityY = Math.abs(wallVelocityY);
			}
			else if (y >= 120)
			{
				wallVelocityY = -Math.abs(wallVelocityY);
			}
		}
	}
}

BounceEvent.as

package
{
	import flash.events.Event;
	public class BounceEvent extends Event
	{
		public static const BOUNCE:String = "Bounce";
		private var _side:String = "none";

		public function get side():String
		{
			return _side;
		}

		public function BounceEvent(type:String, side:String)
		{
			super(type, true);
			_side = side;
		}

		public override function clone():Event
		{
			return new BounceEvent(type, _side);
		}
	}
}

main.as

This is where the real action happens. First we instantiate the ball, movingWall, and the splat objects. Then we set the ball in motion. And then, using hitTestObject() we check when the ball hits the side walls. Using the custom BounceEvent we make an announcement when the ball hits a wall. The event also lets us know which wall has been hit. For the moving wall after checking with hitTestObject() we also need to find out which side of the wall has been hit. For that we check the overlapping of x and y coordinates of the ball and the moving wall.

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.MovieClip;

	public class main extends Sprite
	{
		private var ballVelocityX:Number = 2;
		private var ballVelocityY:Number = 3;
		private var ball:MovieClip;
		private var movingWall:MovingWall;
		private var splat:Splat;
		public function main()
		{
			stage.frameRate = 36;
			setGraphicObjects();
			startBallMotion();
		}
		private function setGraphicObjects():void
		{
			ball = new Ball(100, 100);
			addChild(ball);
			movingWall = new MovingWall(130, 40);
			addChild(movingWall);
			splat = new Splat();
			addChild(splat);
		}
		private function startBallMotion():void
		{
			ball.addEventListener(Event.ENTER_FRAME, moveball)
			addEventListener(BounceEvent.BOUNCE, bounceHandler);
		}
		private function moveball(event:Event):void
		{
			event.target.x += ballVelocityX;
			event.target.y += ballVelocityY;
			sideWallCollision();
			movingWallCollision();
		}
		private function sideWallCollision():void
		{
			if (ball.hitTestObject(wallLeft))
			{
				ballVelocityX = Math.abs(ballVelocityX);
				ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "left"));
			}
			else if (ball.hitTestObject(wallRight))
			{
				ballVelocityX = -Math.abs(ballVelocityX);
				ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "right"));
			}
			if (ball.hitTestObject(wallTop))
			{
				ballVelocityY = Math.abs(ballVelocityY);
				ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "top"));
			}
			else if (ball.hitTestObject(wallBottom))
			{
				ballVelocityY = -Math.abs(ballVelocityY);
				ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "bottom"));
			}
		}
		private function movingWallCollision():void
		{
			if (ball.hitTestObject(movingWall))
			{
				var movingWallLeft:Number = movingWall.x;
				var movingWallRight:Number = movingWall.x + movingWall.width;
				var movingWallTop:Number = movingWall.y;
				var movingWallBottom:Number = movingWall.y + movingWall.height;
				if (ball.x >= movingWallLeft)
				{
					ballVelocityX = -Math.abs(ballVelocityX);
					ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "center left"));
				}
				else if (ball.x <= movingWallRight)
				{
					ballVelocityX = Math.abs(ballVelocityX);
					ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "center right"));
				}
				if (ball.y >= movingWallTop)
				{
					ballVelocityX = -Math.abs(ballVelocityY);
					ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "center top"));
				}
				else if (ball.y <= movingWallBottom)
				{
					ballVelocityX = Math.abs(ballVelocityY);
					ball.dispatchEvent(new BounceEvent(BounceEvent.BOUNCE, "center bottom"));
				}
			}
		}
		private function bounceHandler(event:BounceEvent):void
		{
			trace("Bounce on " + event.side + " side");
			splat.explode(event.target.x, event.target.y);
		}
	}
}

You can download all the files here:

BallBounce.zip





Reading Flash Vars in AS3.0

13 11 2008

Very often your flash app is required to read variables from the wrapper html page. We define the variables as a name-value pairs string in “FlashVars” param tag. Then, read the variable values in Flash using the LoaderInfo object. See the details below:

The HTML looks like this:

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="550" height="400" title="ReadingFlashVars">
	<param name="movie" value="ReadingFlashVars.swf" />
	<param name="quality" value="high" />
	<param name="FlashVars" value="day=Thursday&month=November&year=2008" />
	<embed src="ReadingFlashVars.swf" width="550" height="400" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" FlashVars="day=Thursday&month=November&year=2008"></embed>
</object>

Notice, the param tag with name as FlashVars. It is passing 3 variables to the SWF file – day, month, and year with values as Thursday, November, and 2008 respectively.

Now, the actionscript part goes something like this – you take the params property of the root loaderInfo object and store it in an object reference. Then, using a for in loop, run through each of the name-value pairs.

var displayData:TextField = new TextField();
displayData.width = 300;
displayData.border = true;
addChild(displayData);
displayData.text = " < Display Flash Vars > ";
var objParam:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (var key:String in objParam)
{
	displayData.appendText("\n " + key + " :: " + objParam[key]);
}

Following result should get displayed when the HTML page is loaded in browser:

Read FlashVars in AS3.0

Read FlashVars in AS3.0