Managing multiple collision detection with Flash

In all tutorials covered until now, we have always seen how to determine collisions between a single object and the rest of the objects in the stage, or part of them.

No matter if it was performed using hit test or trigonometry, the point is that in every moment of the game we knew all the objects that could be involved in a collision detection.

For example, collision between one ball and the state, or one bullet and enemies, and so on.

Sometimes we have to manage multiple collision detection.

Try to imagine a shoot’em up game, where several projectiles are fired against enemy ships, or a breakout/arkanoid clone where a power up multiplies the number of ball in the stage, or a pool game where every ball can hit every other ball or the table bounds.

Since we do not know how many objects there are in the stage, we need a routine to scan all objects and determine if they collide among each others.

There are two types of multiple collision: the first is when we have two (or more) separate types of objects that can collide. For example, in a shoot’em up we know we do not care about collisions among enemy ships themselves while we care about collisions between enemy ships and bullets.

In the following example we have two classes of objects: the evil red squares and the good blue squares. When a red square hit a blue square, they both die. We won’t care about collisions among squares of the same color.

In the first step, I’ll put on the stage 20 blue squares moving horizontally and 20 red squares moving vertically.

To do this, I created a blue square object linkaged as “blue” and a red square objects linkaged as “red”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for (x=1; x<=20; x++) {
	blue = _root.attachMovie("blue", "blue_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	blue.speed = 2+Math.random()*3;
	blue.onEnterFrame = function() {
		this._x += this.speed;
		if (this._x>500) {
			this._x -= 500;
		}
	};
}
for (x=1; x<=20; x++) {
	red = _root.attachMovie("red", "red_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	red.speed = 2+Math.random()*3;
	red.onEnterFrame = function() {
		this._y -= this.speed;
		if (this._y<0) {
			this._y += 350;
		}
	};
}

Line 1: Loop to be executed 20 times

Line 2: Attaching the blue movieclip at the next highest depth and placing in a random place of thes tage

Line 3: Giving the blue movieclip a random speed

Line 4: Beginning of the function to be executed at every frame

Line 5: Moving the blue square according to its speed

Lines 6-8: If the blue square reaches the right end of the stage, then have it reappearing from the left side

Lines 11-20: Same routine with red squares execpt they are moving vertically

Now we have a bunch of boxes moving.

What we want is to check if any blue box hits any red box

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var blue_array = new Array();
for (x=1; x<=20; x++) {
	blue_array.push("blue_"+_root.getNextHighestDepth());
	blue = _root.attachMovie("blue", "blue_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	blue.speed = 2+Math.random()*3;
	blue.onEnterFrame = function() {
		this._x += this.speed;
		if (this._x>500) {
			this._x -= 500;
		}
	};
}
for (x=1; x<=20; x++) {
	red = _root.attachMovie("red", "red_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	red.speed = 2+Math.random()*3;
	red.onEnterFrame = function() {
		this._y -= this.speed;
		if (this._y<0) {
			this._y += 350;
		}
		for (x in blue_array) {
			if (this.hitTest(_root[blue_array[x]])) {
				_root[blue_array[x]].removeMovieClip();
				this.removeMovieClip();
				blue_array.splice(x, 1);
			}
		}
	};
}

Line 1: Creation of an array called blue_array that will contain blue boxes instances.

Line 3: Pushing in the array the name of the box we are about to create. It’s very important to place this line before the creation line (line 4) or the getNextHighestDepth() function will return the (obviously) next highest depth. I mean that if you are about to create your first box the next highest depth is n, if you already created it then you next highest depth will be n+1. The push method adds one or more elements to the end of an array and returns the array’s new length.

Line 21: loop that scans all elements in the blue_array array

Line 22: checking if a hit test between the red square and the x-th element in the blue_array (the x-th blue square) happens.

Lines 23-25: if positive, removing the red square movieclip, the blue square movieclip and the element from the blue_array array. The splice method removes n elements (in our case 1) from the m-th position (in our case x) in the array.


You may need to refresh the page to see the code in action

Being the “easy” case, you may notice there are lots of collision detections:in the initial case there are 20 blue squares that may collide with 20 red squares. That is as much as 400 hit test performed on every frame.

In a 30fps shooter, this means 12000 hit tests per second.

Think about it when you are going to make a game.

The “hard” case happens when any movieclip may hit any other movieclip, for example in a pool game, or in this case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var blue_array = new Array();
for (x=1; x<=40; x++) {
	blue = _root.attachMovie("blue", "blue_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	blue.xspeed = 2+Math.random()*3;
	blue.yspeed = 2+Math.random()*3;
	blue.onEnterFrame = function() {
		this._x += this.xspeed;
		this._y -= this.yspeed;
		if (this._x>500) {
			this._x -= 500;
		}
		if (this._y<0) {
			this._y += 350;
		}
	};
}

This is the same case as the one with blue and red boxes, execpt there are only blue boxes.

Let’s examine now the collision engine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var blue_array = new Array();
for (x=1; x<=40; x++) {
	blue_array.push("blue_"+_root.getNextHighestDepth());
	blue = _root.attachMovie("blue", "blue_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	blue.xspeed = 2+Math.random()*3;
	blue.yspeed = 2+Math.random()*3;
	blue.onEnterFrame = function() {
		this._x += this.xspeed;
		this._y -= this.yspeed;
		if (this._x>500) {
			this._x -= 500;
		}
		if (this._y<0) {
			this._y += 350;
		}
		for (x in blue_array) {
			if (this != _root[blue_array[x]]) {
				if (this.hitTest(_root[blue_array[x]])) {
					_root[blue_array[x]].removeMovieClip();
					this.removeMovieClip();
					blue_array.splice(x, 1);
				}
			}
		}
	};
}

Line 17: In the loop cycling through the array, before performing the hit test I must be sure I am not testing the hit of a movie with itself.

The remaining code is the same as for blue/red boxes.


You may need to refresh the page to see the code in action

Seems to work well but… it doesn’t.

Try to imagine the first movieclip testing the hit with the second one, the third, fourth and so on.

Now we have the second movieclip testing the hit with the first one, the third, fourth, and so on.

As you can see, I checked the hit between the first and the second movieclip two times: one when I check between the 1st and the 2nd and one when I check between the 2nd and the 1st.

What a waste of time!!

To prevent this, we need this fix:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var blue_array = new Array();
for (x=1; x<=40; x++) {
	blue_array.push("blue_"+_root.getNextHighestDepth());
	blue = _root.attachMovie("blue", "blue_"+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:Math.random()*500, _y:Math.random()*350});
	blue.xspeed = 2+Math.random()*3;
	blue.yspeed = 2+Math.random()*3;
	blue.onEnterFrame = function() {
		this._x += this.xspeed;
		this._y -= this.yspeed;
		if (this._x>500) {
			this._x -= 500;
		}
		if (this._y<0) {
			this._y += 350;
		}
		for (x in blue_array) {
			if (this.getDepth()>_root[blue_array[x]].getDepth()) {
				if (this.hitTest(_root[blue_array[x]])) {
					_root[blue_array[x]].removeMovieClip();
					this.removeMovieClip();
					blue_array.splice(x, 1);
				}
			}
		}
	};
}

Now line 17 performs the test only if the target movieclip has a depth lower than its own depth. In this case there is no test for the 1st movieclip, the 2nd performs the test only with the 1st, the 3rd with the 2nd and the 1st and so on.


You may need to refresh the page to see the code in action

In the previous case to perform all tests in a frame I needed 40*39 = 1560 tests

In this one I need only 39+38+37…+2+1 = 780 tests

And this is the right way.

That’s all you need to know about multiple collision detection, now we can start planning a good shooter game.

Download the source codes and give me feedback.

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (4 votes, average: 5.00 out of 5)
Loading ... Loading ...
If you found this post useful, please consider a small donation.
» Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.

14 Responses to “Managing multiple collision detection with Flash”

  1. abhilash on June 21st, 2007 10:50 am

    it was great tutorial and check your mail, i sent you the 2nd part of my game.

  2. Evan on June 21st, 2007 11:21 am

    Wow Emmanule.

    You must have psychic powers or something because this tutorial is just what I needed at the moment, lol. Yesterday, while waiting for your next tut I decided to create a mini-game where random tanks come flying at you. I just got stuck on finding a way to have the tanks detect if they were shot. You’ve answered my prayers. :P.

  3. Evan on June 21st, 2007 12:21 pm

    Emanuele* Sorry. :D

  4. craig on June 24th, 2007 12:24 pm

    NICE!!! Came up with another method after looking at http://www.kirupa.com/developer/actionscript/multiple_collision2.htm and your coding.

    a rough formula outline, will be posting a sample on my site soon

    var num:Number=5;

    //loop thru every object except last object
    for(var i:Number=0;i

  5. eblup on June 25th, 2007 6:55 am

    looks like the zombie infection simulation on the internet

  6. Fyfey on June 25th, 2007 3:20 pm

    Thanks alot Emanuele. I needed to detect collision between multiple homing missiles and this does the job perfectly!!

  7. yod on August 13th, 2007 11:53 am

    Thanks, this is cool trick.
    this.getDepth()>_root[blue_array[x]].getDepth()

  8. Melissa on September 4th, 2007 8:52 pm

    I’m working on a game where 5 different objects fall from the sky…I already have everything falling randomly and duplicating when they hit the ground then falling randomly again. The problem is in the hit test…the results for 3 of the objects should be the same when they hit the object on the ground and the result for the other 2 should be the same. How do I group the three and then the two into a variable so that I just have 2 hittest if and else statements? I’d really appreciate your help…I’m just a flash beginner!

  9. Rachel on February 8th, 2008 11:12 pm

    What version of actionscript is this?

  10. Xodus on May 2nd, 2008 6:01 pm

    Rachel: its AS 2.0

    So, could you then refer to the blue boxes as
    [blue_array], why do you need to refer to it as [blue_array[x]]?

  11. Ian on May 17th, 2008 7:32 pm

    Wow, you always seem to have just the thing I’m looking for. I’ve looked all around the web and this is the ONLY tutorial about collision detection with mutiple duplicated movieclips.
    By the way, will this work for objects like circles?

  12. Noah on March 31st, 2009 8:23 am

    Always a pleasure to read your tutorials. Straight to the point, easy to follow, perfect results.

    LOVE YOU!!!

  13. programer on April 14th, 2009 10:10 pm

    Thank You!!!

    This has helped so much and is what I needed because I am new with arrays, now I just have to test it with my game.

  14. Yasha on June 18th, 2009 6:19 am

    yeah – agree – this is the stuff

    this.getDepth()>_root[blue_array[x]].getDepth()

    THANK YOU!

Leave a Reply




flash games company