Tutorials

February 16, 2009

AS3 Flash Games for Beginners: Registering Hit Tests

basics4_tn

Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

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.

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

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

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.

basics1_7step1-3

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

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);
		}
 
	}
 
}

Alright I’m done. Compile your file and you should get something like this:

Next time we’ll create effects when a ship is destroyed so it’s not so dull and we’ll do something else with our ship to make it look cool as well.

Here’s the final source code: Registering Hit Tests Zip Archive

Similar Posts:


Share on TwitterShare on TumblrSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit


About the Author

Par
Hey! Don't be surprised, I'm a flash developer. While Flash is definitely one of my favorite languages to develop in, most of all I just like making games. If you want to see the games I've developed so far head over to my website, DigitallyBold, in the link below. If you want to know more about what I'm working on now and in the future be sure to follow me on twitter.




38 Comments


  1. dimebagplan

    This kind of shooter cover a lot of interesting stuffs !
    The tutorial explain very good, and the code is very clear.
    Thanks !!!


  2. Tee

    I was curious I am coming up with an error 1119 in my stingrbullet class and i dont know why it says

    1119: Access of possibly undefined property hit through a reference with static type com.asgamer.basics1:Ship.


  3. Tee

    Never mind Figured it Out GYea!
    Good informative tutorial Nice Post!


  4. Jonas

    Great tut. but why do you have to use packages?? That just messes things up..


  5. Par

    How exactly does it mess anything up? If the extra work involved is too difficult for you to deal with then don’t do it. But when somebody else comes along with the exact same class name as you and it gives you a problem, you’ll wish you used a package.


  6. jacobs

    good, good, tutorial.
    I really understood it.


  7. THIS GUY IS AWESOME

    Hey bro,
    some epic tutorial you have, keep up the good work!

    All the other tutorials have heaps of un-understandable SHIT that doesn’t make any sense at all. your nearly as awesome as me.
    Awesome guy signing out.


  8. Nick

    I cant figure out that error 1119 myself and i have been tryin alot


  9. Avenk

    I think it would be a good idea..
    Thank’s!


  10. josh

    hey everyone i was wondering if anyone could help me out im making a putt putt game and i have a movieclip named ball and a movie clip named hole and when they touch i need a button to pop up to take you to the next scene and i was wondering if anyone know what the code would be for that any help would be greatly appreciated thank you.


  11. Dennis

    Hey, I am also getting the following error in my StingerBullet.as:

    1119: Access of possibly undefined property hit through a reference with static type com.asgamer.basics1:Ship.

    Tee, if you see this can you please post how you fixed this problem?

    Otherwise, if it’s not too much trouble, can you please help me and some others out Par?
    I have been trying to figure this out for a while, following the tutorial exactly and replacing my tweaked as with your as doesn’t solve anything. I keep getting this error.

    Any help would be greatly appreciated. Great job on these tutorials by the way. Keep it up :)


  12. Dennis

    Okay nevermind about my previous post. I forgot to set the instance names of the hitBox for the ships. Sorry about that.

    Keep up the good work man, fantastic tutorials with easily changed code that a beginner can understand.


  13. Janrah

    can anyone help me with my problem because i have an error 1119
    saying:
    1119: Access of possibly undefined property hit through a reference with static type com.asgamer.basics1:Ship

    I would really appreciate if anyone can help. Thanks in advance.


  14. Janrah

    can anyone help me fix a 119 error?


  15. robin

    thank you very much for these tutorials, I’ve got a problem though with the hitboxes, actually, when my blueLaser hits, the enemy desappears but the hit box still exists and do not move, it creates like an invisible wall which stops the blueLaser and makes it desappear before it reaches the top side of the stage.
    So my problem is Why the hitBoxes of the enemies still exist on the stage when the blue laser hits ?
    PLEASE GUYS HELP ME OUT WITH THIS :( I can’t move out if I don’t fix this issue :(


  16. Rory

    I am also having the 1119 error. been sifting through for a while now. probably some parenthesis missing somewhere….


  17. Rory

    Ok. I had mis-typed the “hit” calling the MovieClip in the ‘hitTestObject(Engine.enemyList[i].hit)’ if statement. And had mis labled the hit box on the library ship.

    So I guess if others have the same issue with 1119. Check those areas around all your hit box communications.


  18. KrackMuffin

    i got the access error too its due to the array being private set it to public instead this helped me i hope it helps you


  19. Nathan

    This is a great tutorial, but I did spot a error.

    For example you tell us to set the linkage as “.SmallImplosion” and then you tell us to call out Action Script “SmallExplosion”.

    It is a small error, but it WILL prevent the script from working.


  20. Journey Stephen

    Wow….

    Thanks a lot bro for this…. you don’t know how you helped me out with this…. Keep posting great stuff!! Cheers!!


  21. pepeu

    Hi there. I just wanted you to know there is a typo in the tutorial. SmallImplosion is called SmallExplosion at one time where we are supposed to craate and save a new AS-file.


  22. hi again ^^

    still getting through the tutorial, still finding it great…my ship shoots, the enemy shoots, both can hit…what else would i have from this…

    peace, gotta go to the next page


  23. Ahsan

    I am getting this thingy :

    1119: Access of possibly undefined property hit through a reference with static type com.asgamer.basics1:Ship.

    any help ?

    btw, the tutorial has been very nice and good….a few typos here and there which will be good if edited out. overall very helpful tutorial. :)

    -
    ahsan


  24. Surely the Conditional Statement in the loop function of SmallImplosion is unnecessary. I can see how the condition

    if(currentFrame == totalFrames)

    will call a function in a one frame movie, since both currentFrame and totalFrames = 1. But since we already added an Event Listener for an ENTER_FRAME event to call loop, we only need to reference the call to removeSelf() inside the loop function.

    Every time we enter the frame, 24 times per second, the Listened for event occurs, loop is called, and in turn loop calls removeSelf().

    Surely using if(currentFrame == totalFrames) is redundant in this case? If there is another reason why we should include if(currentFrame == totalFrames), please let me know. I have removed this Conditional, and the program compiles and runs perfectly without it.


  25. Cry Bayb

    Heyyy is there going to be a scoring?


  26. Reapering

    Okay this error that pops up,
    saying:
    1119: Access of possibly undefined property hit through a reference with static type com.asgamer.basics1:Ship

    i keep getting it too, but later i figured out how to fix it and probably what you said was a little misleading. The part where you said to create a rectangle movieclip inside the ship(i thought you meant inbetween the ship image artwork, but its not), so heres what i did:
    1. Place “ship” movieclip from the library to stage
    2. double click the “ship” movieclip and it brings up a new timeline within the scene1
    3. Now from here, create the rectangle “hitbox” movieclip and give the instance name “hit”

    That should do XD and nothing wrong with my code.Hope this helps some people out.


  27. Ashley

    Hi, great explanation. Do you know if there is a way to do the opposite if hitTestObject to tell when two clips are no longer touching. I thought about using ! but am not sure how to go about it. Any help greatly appreciated.


  28. Beranger de Roquefeuil

    A big Thank, Man. The beginner I am really needed this tutorial to practice with fun ! Really good Job !


  29. Ben

    Okay, so everything seems to be working alright – but I am getting an error… This may not be an issue but it does seem to lag the program when it occurs.

    Error #2007 – hitTestObject must be non-null

    This is occurring in the loop function of my bullet class, and only happens if I continue firing through the ship as it is being “destroyed”. (I have a higher rate of fire than the demo).

    It seems like maybe the ship still exists and is getting hit even though it has been removed from the enemy array? And therefore the hitTestObject has nothing to reference.

    How can I fix this?


  30. Joe

    hey, thought I’d point out: you still need to remove your stingers from the array of enemies.

    Good catch on removing the event listeners, but don’t forget that last step. print the length of your array if you need proof.


  31. Mike

    The reason I was getting 1119 was because I wrote:

    private static var enemyList:Array = new Array();
    ——-
    which should have been:

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

    This is a great tutorial by the way. The best one I have come across.


  32. Joe

    sorry, just looked in the Engine document class and discovered that you do remove the enemies from the array in there. my bad…. I’ve seen too many people forgetting to do that and teaching others the bad habit.


  33. Cruz

    first of all. great tutorial! i managed to go through the entire tutorial.
    now i’m having a little problem.

    i decided to create my own adventure game, similar to “the legend of zelda”. i’m trying to apply all i’ve learned in this tutorial.
    but i came across a problem with the hitbox testing.
    (i’m using the hitbox for areas you cannot enter, for example, trees and rocks)

    i’m having trouble applying the hitbox code to my “hero”.as and “background”.as…

    could you tell me what code i would need to make this happen?

    help would be very appreciated (:


  34. Mayank

    Hey guys!!!!
    This post is for everyone getting the 1119 error…….
    I had a tough time finding the solution as those posted did not work for me…….the solution turnes out to be a VERY SIMPLE one!!!!!
    just go to file->publish settings and turn on automatically declare stage instances…..SIMPLE!!!!!
    it works….REALLY!!!!
    tell me if it works……


  35. you are really good. with packages and classes and stuff, you must have been a CS major or something. I feel dumb but now smart after reading this!


  36. Idk

    Hey thanks for the Tutorial. .hit does not exist. I get this Compiler Error about the access of an undefined property “hit”.


  37. Ian

    Wonderful set of tutorials.

    I have been using the basis of your codes and apply it to a game i’m working on, but I’m now stuck with the hitTest.

    The equivalent in my game in relation to the one featured here would be that the “hitTest” be carried out between the ship and the stinger, not the bullets. Therefore what code would I need and where would I put it if I wanted just the ship and the stinger to be the hittest?

    All help and advice very much welcome.
    Thank you!!!!!


  38. I really thought this tutorial would help me finally get the hitTestObject code to work. But it didn’t. I keep getting a Error #1009: Cannot access a property or method of a null object reference. Which means it’s not finding my Ship or the hitbox. I’ve tried everything.



Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">


Advertisement