You are on page 1of 9

Okay so hit tests. Hit tests simply are a check to see if two objects are touching one another.

There’s plenty of ways of doing them and every shooter game needs them. AS2 had a nice little
function called hitTest, AS3 has two functions…. hitTestPoint and hitTestObject. So what’s new
about this hitTestPoint and hitTestObject and which one do you use? We’ll discuss it and how to
make our bullets hit enemies and enemy bullets hit us.

You are reading AS3 Flash Games for Beginners Read more from this series of
articles.

 AS3 Flash Games for Beginners: Adding Library Objects to Stage with AS3
 AS3 Flash Games for Beginners: Character Movement / Handling Multiple Keypresses
 AS3 Flash Games for Beginners: More Advanced Character Movement
 AS3 Flash Games for Beginners: Level Mechanics and Animated Backgrounds
 AS3 Flash Games for Beginners: Firing Weapons with Delays
 AS3 Flash Games for Beginners: Learn How to Make Enemies with Basic AI!!!
 AS3 Flash Games for Beginners: Registering Hit Tests
 AS3 Flash Games for Beginners: Using Frame Labels and Art Tweening
 AS3 Flash Games for Beginners: Scores, HUDS, and User Interface

This post is one of many in a series titled AS3 Flash Games for Beginners. If you haven’t
followed the series from the beginning, I strongly recommend you return to the first tutorial and
follow through to here. If you don’t  return to the beginning you will want to download the
source code from the previous tutorial here. Please keep in mind that if you have issues
understanding parts of this tutorial and you didn’t return to the beginning, you’ll likely find
clarity from doing so.

First of all, I’m probably going to setup our Hit Test a lot differently then you’ve seen in the
past. I use the normal Flash provided functions; however, I make a different use of them. If you
don’t know a lot about hit Tests, there is a lot of talk about them and you can find information on
them everywhere. Why? Because games need hit tests and certain methods work better than
others depending on how it’s needed. My method is very simple (which is why I use it), and it’s
a relatively accurate hit test.

Step 1: Setting up our Ships to be Hit

So here’s what we are going to do. Goto our Ship in the library. Create a new layer and draw a
box with the Rectangle tool that covers as much area of our ship as possible while staying inside
the ship as much as possible. Hope that’s not confusing… my box looks like this.
Green Box representing our hit area of our Ship

Okay, right click our box then Convert to Symbol… and name it hitBox then make it a
MovieClip with the Registration in the center. Now, we just need to name the instance. So click
our hitBox to highlight it and in our Properties window you’ll see a white textbox with gray text
saying <Instance Name>.  Make the instance name “hit” (without quotes). Here’s a screenshot:

Setting up an instance of our hitBox MovieClip

Nice, now guess what? We need to do this to our Stinger ship as well. So let’s open our Stinger
ship MovieClip and pull our hitBox clip into it. Simply click and drag hitBox from the Library
onto a new layer inside the Stinger ship MovieClip. Now grab the Free Transform Tool (F) and
resize hitBox to be the size you need it to cover the Stinger ship. Mine looks like this.

Large hit area for our enemy ship


Just name the instance of the box hit like we did before. Now double click our big box “hit”
MovieClip to jump inside it.  Select our rectangle and goto our Color window (SHIFT+F9) and
change the alpha to 0. This will make our “hit” MovieClip invisible.

Let me explain the reasoning behind these hit boxes. First of all, Flash’s hitTestObject function
checks if two objects hit each other. However, it checks the bounding box around our object not
the pixels inside of it. So if a projectile comes inside our bounding box, it’s a hit even if it
doesn’t touch the artwork of our ship. By creating the hit boxes we now have an area that we can
do the hit test on that is more appropriately the size of our ship. Yes the tip of our ship and it’s
wings are not entirely covered but as you’ll see when you test this momentarily it works
extremely well.

Step 2: Programming our HitTest

Alright, this is going to be easy… We’ve got a few checks and one or two minor adjustments and
our hitTests will be working perfectly. We’ll only check for a hit with in our bullet classes and
not our ships. This will prevent us from checking for the same hitTest in two places which will
only slow our game down and is entirely useless (as one check works great).  So open our
StingerBullet class, we’re going to add one snippet of code to the loop function (at the bottom):

if (hitTestObject(target.hit))
{
trace("hitME");
removeSelf();
}

Alright let’s break it down:

 hitTestObject(target.hit). The hitTestObject function returns a boolean variable of


either true or false depending on whether or not the two objects are hitting one another. If
you only see one object here, that’s because this.hitTestObject(target.hit) is the same
thing… It’s like basic English. If I say “Get the ball”, you is implied… it’s the same as
“You get the ball”.  Well with our function calls “this” is implied. Therefore, our two
objects being checked is this(this stinger bullet) and target.hit. If you remember target is
our Ship variable that we passed through… and hit is the instance of our hitBox
MovieClip that we created just a few seconds ago. If you had named the instance
hitboxarea then we’d be checking with target.hitboxarea instead.
 trace(”hitMe”); This just makes Flash send a message out that says hitMe everytime our
Ship is hit. It’s good for testing because it lets us know the condition was met but useless
for anything else. So feel free to use it during testing but you might as well delete them
all before you release.
 removeSelf(); this calls our function that removes our bullet from the stage… We created
this in an earlier tutorial.

Alright so we have one more problem… I forgot to tell you to remove your EnterFrame event
listener from your bullet. Do that now in the removeSelf function. Here’s what your
StingerBullet.as file should look like now:
package com.asgamer.basics1
{
 
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
 
public class StingerBullet extends MovieClip
{
 
private var stageRef:Stage;
private var target:Ship;
 
private var vx:Number;
 
public function StingerBullet(stageRef:Stage, target:Ship,
x:Number, y:Number, vx:Number) : void
{
this.stageRef = stageRef;
this.target = target;
this.x = x;
this.y = y;
this.vx = vx;
 
addEventListener(Event.ENTER_FRAME, loop, false, 0,
true);
}
 
private function loop(e:Event) : void
{
x += vx;
 
if (x > stageRef.stageWidth || x < 0)
removeSelf();
 
if (hitTestObject(target.hit))
{
trace("hitME");
removeSelf();
}
}
 
private function removeSelf() : void
{
removeEventListener(Event.ENTER_FRAME, loop); //don't
forget to add this
if (stageRef.contains(this))
stageRef.removeChild(this);
}
 
}
 
}

Alright, our StingerBullet is ready. Let’s make our LaserBlue class check if it hits enemies. First
though, we have to be able to find all the enemies currently on the stage to see if we are hitting
them. We created an enemyList array in Engine earlier for just this purpose… but we need to
make a quick change to it. Open up Engine.as and change it from this:

private var enemyList:Array = new Array();

to this:

public static var enemyList:Array = new Array();

Here’s the reasoning… because it is a static var it would maintain the same value between all
instances of the Engine class(we only have one Engine running so we really don’t have to worry
about that). Also it being static and public means we can access it by calling Engine.enemyList
whenever we need it. We’ll need to call it in our LaserBlue class so we can tell what enemies to
check if we are hitting.

So open up LaserBlue.as now and in our loop function, at the bottom we’re going to add our
hitTest:

for (var i:int = 0; i < Engine.enemyList.length; i++)


{
if (hitTestObject(Engine.enemyList[i].hit))
{
trace("hitEnemy");
Engine.enemyList[i].takeHit();
removeSelf();
}
}

This looks a little different than before.. let’s break it down:

 First we for loop through all the enemies in enemyList. You should understand how a for
loop works as we have discussed it previously.
 Then we check for a hitTest again, this time between our LaserBlue and the hit instance
in each of our enemy ships.
 If it returns true we trace “hitEnemy” and call the takeHit function of our enemy… One
problem, they don’t have a takeHit function yet. We’ll have to make one.
 Then we call removeSelf(); to get rid of the laser.

Alright now we gotta open Stinger.as so we can add that takeHit function. We should of done
something like this with our Ship.as class as well but I’ve got plans to do something different
with this in our next tutorial, so keep an eye out for it. In Stinger.as simply add a public takeHit
function that calls removeSelf(). Why not just call removeSelf? Well one it’s private so we can’t
(unless we make it public) but also because we’re going to add some stuff to takeHit in the next
tutorial as well Also I made a couple adjustments to make it easier to hit the stinger enemy and
make it more fun dodging his bullets. I changed vy to 4, ay to .2, and the bullet speeds in
fireWeapon to 8 and -8.  But tweak these however you want, it’s your game. Your Stinger.as
should now look like this:
package com.asgamer.basics1
{
 
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
 
public class Stinger extends MovieClip
{
 
private var stageRef:Stage;
private var vy:Number = 4;
private var ay:Number = .2;
private var target:Ship;
 
public function Stinger(stageRef:Stage, target:Ship) : void
{
this.stageRef = stageRef;
this.target = target;
 
x = Math.random() * stageRef.stageWidth;
y = -5;
 
addEventListener(Event.ENTER_FRAME, loop, false, 0,
true);
}
 
private function loop(e:Event) : void
{
vy += ay;
y += vy;
 
if (y > stageRef.stageHeight)
removeSelf();
 
if (y - 15 < target.y && y + 15 > target.y)
fireWeapon();
}
 
private function fireWeapon() : void
{
stageRef.addChild(new StingerBullet(stageRef, target,
x, y, -8));
stageRef.addChild(new StingerBullet(stageRef, target,
x, y, 8));
}
 
private function removeSelf() : void {
 
removeEventListener(Event.ENTER_FRAME, loop);
 
if (stageRef.contains(this))
stageRef.removeChild(this);
 
}
 
public function takeHit() : void
{
removeSelf();
}
 
}
 
}

Okay, so at this point if you compile the game it should work. If a bullet hits a ship it disappears.
If a bullet hits an enemy ship it disappears. If a bullet hits your ship… nothing happens to your
ship.  So let’s just make a small implosion when our ship gets hit.

Step 3: Creating Bullet Explosions

Create a new MovieClip (CTRL+F8) and name it implosion.  Now inside the MovieClip draw a
small yellow circle about the size of your enemy bullet. Go down 5 frames and right click and
select Insert Keyframe. In your new keyframe, resize your circle til it’s almost invisible.  Now
right click in the area between your first and last keyframe and click Create Shape Tween. You
should end up with your timeline looking something like this:

Shot of timeline after creating a small implosion MovieClip

Alright now right click your MovieClip in the Library (CTRL+L) and select Linkage…  export
for ActionScript and set it’s class to “com.asgamer.basics1.SmallImplosion”

Now you know what’s next…. create a new file in the com/asgamer/basics1 directory and call it
SmallExplosion.as… Now fill that blank document up with this ActionScript.

package com.asgamer.basics1
{
 
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
 
public class SmallImplosion extends MovieClip
{
 
private var stageRef:Stage;
 
public function SmallImplosion(stageRef:Stage, x:Number,
y:Number)
{
this.stageRef = stageRef;
this.x = x;
this.y = y;
addEventListener(Event.ENTER_FRAME, loop, false, 0,
true);
}
 
private function loop(e:Event)
{
if (currentFrame == totalFrames)
removeSelf();
}
 
private function removeSelf() : void
{
removeEventListener(Event.ENTER_FRAME, loop);
 
if (stageRef.contains(this))
stageRef.removeChild(this);
}
 
}
 
}

Pretty simple really… we’ve discussed 90% of this before… let’s break it down:

 we set some imports, create our class that extends MovieClip, and setup a class variable
called stageRef.  Our constructor function needs the stage reference and an x and y. We
then set our variables according to the parameters passed into the constructor.  We create
an event listener that fires everytime we enter the frame which calls the loop function.
 Inside loop we check for one thing… if (currentFrame == totalFrames) currentFrame
and totalFrames are variables we inherited from MovieClip. Because MovieClips operate
on the timeline they always have a current frame that they are on and totalFrames is the
number of frames in the MovieClip’s timeline that are being used. So if our currentFrame
is equal to totalFrames (which is the same as the last frame number) then we call
removeSelf.
 removeSelf is like all the other removeSelf’s that we have made. It kills the event listener
and removes the MovieClip from the stage.

Alright…. one last thing. When an enemy bullet hits our ship we need the small implosion to
appear. So let’s open back up StingerBullet and add this line inside the if (hitTestObject)
condition: stageRef.addChild(new SmallImplosion(stageRef, x, y));.

So our StingerBullet.as file should look like this.

package com.asgamer.basics1
{
 
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
 
public class StingerBullet extends MovieClip
{
 
private var stageRef:Stage;
private var target:Ship;
 
private var vx:Number;
 
public function StingerBullet(stageRef:Stage, target:Ship,
x:Number, y:Number, vx:Number) : void
{
this.stageRef = stageRef;
this.target = target;
this.x = x;
this.y = y;
this.vx = vx;
 
addEventListener(Event.ENTER_FRAME, loop, false, 0,
true);
}
 
private function loop(e:Event) : void
{
x += vx;
 
if (x > stageRef.stageWidth || x < 0)
removeSelf();
 
if (hitTestObject(target.hit))
{
trace("hitME");
stageRef.addChild(new SmallImplosion(stageRef,
x, y));
removeSelf();
}
}
 
private function removeSelf() : void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
 
}
 

You might also like