In the last section, we created an asteroids class to easily create a variety of asteroids, as well as move them around on screen.
In this section, we’ll create a way to detect collisions between the asteroids and the ship or bullets, and create particle explosions when the collisions happen, as well as break apart asteroids upon collision.
Adding Collision Detection to Bullets, Asteroids and the Ship Class
We now have to detect when a collision has happened between and asteroid and either the ship or a bullet, and create an explosions when one has happened.
Since only asteroids need to be interacted with, we will only need to do collision detection on them, but against both the ship and bullets.
We’ll want to create an explosion object to be created whenever a collision has occured. So create a new class with a base class of type MovieClip in the Entities folder again.
Explosion.as
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | package Entities { import flash.display.MovieClip; import flash.geom.Point; /** * ... * @author Chris Moeller */ public class Explosion extends MovieClip { private var radius:Number; public var finished:Boolean; private var size:int; private var random_offsets:Array; private var random_sizes:Array; private const num_points:int = 12; public var life:Number; public var max_life:Number; public function Explosion(x:int, y:int, max_life:Number, size:int = 0 ) { this.x = x; this.y = y; this.size = size; this.life = Game.current_time; this.max_life = max_life; graphics.lineStyle(2, 0x333333); finished = false; random_offsets = new Array(); random_sizes = new Array(); var high:Number = 10 ; var low:Number = 0; var high2:int = 3; var low2:int = 1; for (var i:int = 0; i < num_points; i++) { var random_x:Number = Math.floor(Math.random() * (1 + high - low)) + low+i; var random_y:Number = Math.floor(Math.random() * (1 + high - low)) + low+1; random_offsets.push(new Point(random_x, random_y)); random_sizes.push(Math.floor(Math.random() * (1 + high2 - low2)) + low2); } } public function Update():void { //going to want to draw points around the outside of a circle of radius size, and have it increasing //so need to go around the circle (centered at x,y=0,0) and draw lines outward graphics.clear(); var selected_color:int = 16-Math.round((Game.current_time-life) / max_life*16); var color_val:String = selected_color.toString(16); var color:uint = uint("0x" + color_val + color_val + color_val + color_val + color_val + color_val); graphics.beginFill(color); for (var i:int = 0; i < num_points; i++) { graphics.drawRect( size * Math.cos(((i + 1) * 360 / num_points) * (Math.PI / 180)) + random_offsets[i].x, size * Math.sin(((i + 1) * 360 / num_points) * (Math.PI / 180)) + random_offsets[i].y, random_sizes[i], random_sizes[i]); } graphics.endFill(); size += ((max_life-(Game.current_time-life))/max_life)*5; } } } |
Explosion Function/Constructor: We create two arrays– one to hold all the random offsets of the particles we will create, and for the random sizes of the particles.
Update Function: The main objective of this function is to update the position of all the particles of the explosion, with the size of the explosion increasing each frame, as well as the color and alpha value fading each time.
Next, we also have to change “game.as” to actually run the collision detection for each frame.
We have to handle when a collision has happened by creating an explosion, removing the asteroid and bullet, and creating two smaller asteroids, if applicable.
Game.as
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | package { import Entities.Asteroid; import Entities.Bullet; import Entities.Explosion; import Entities.Ship; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.display.Stage; import flash.events.Event; import flash.events.KeyboardEvent; import flash.utils.getTimer; public class Game { public var stage:Stage; public var ship:Ship; private const LEFT:int = 37; private const UP:int = 38; private const RIGHT:int = 39; private const SPACE:int = 32; private const DOWN:int = 40; public static var stageWidth:int; public static var stageHeight:int; public static var current_time:Number; //used to track the time of the current frame private var bullets:Array; //used to hold all the bullets private var firing_delay:Number; //the delay before creating a new bullet when the space bar is held down private var last_fired:Number; //the time the last bullet was created private var bullets_max_life:Number; //the max life of the bullets private var space_down:Boolean; //Either set to true if the spacebar is being held down, or false if released private var asteroids:Array; private var explosions:Array; public function Game(stage:Stage) { this.stage = stage; stageHeight = stage.stageHeight; stageWidth = stage.stageWidth; trace("Game created"); //create the ship ship = new Ship(stage.stageWidth / 2 - 5, stage.stageHeight / 2 - 10); stage.addChild(ship); //now for input stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp); bullets = new Array(); firing_delay = 200; last_fired = 0; bullets_max_life = 1000; space_down = false; asteroids = new Array(); //setup four first asteroids asteroids.push(new Asteroid(stageWidth / 5, 2 * stageHeight / 3, 0, 0, 0)); asteroids.push(new Asteroid(stageWidth / 5, stageHeight / 4, 0, 1, 0)); asteroids.push(new Asteroid(2*stageWidth / 3, 1 * stageHeight / 3, 0, 2, 0)); asteroids.push(new Asteroid(2*stageWidth / 3, 5 * stageHeight / 5, 0, 3, 0)); for (var i:int = 0; i < asteroids.length; i++ ) stage.addChild(asteroids[i]); explosions = new Array(); } public function Update(e:Event):void { current_time = getTimer(); ship.Update(); if (space_down && current_time-last_fired > firing_delay) { var angle_rad:Number = ship.rotation * Math.PI / 180; bullets.push(new Bullet(ship.x, ship.y, current_time, angle_rad)); last_fired = current_time; stage.addChild(bullets[bullets.length - 1]); } var bullets_length:int = bullets.length - 1; for (var i:int = bullets_length; i > -1;i-- ) { bullets[i].Update(); if (current_time-bullets[i].life > bullets_max_life) { stage.removeChild(bullets[i]); bullets.splice(i, 1); } } for (var k:int = asteroids.length-1; k > -1;k-- ) asteroids[k].Update(); //removing explosions var explosions_length:int = explosions.length - 1; for (var m:int = explosions_length; m > -1; m-- ) { explosions[m].Update(); if (current_time-explosions[m].life > explosions[m].max_life) { stage.removeChild(explosions[m]); explosions.splice(m, 1); } } //now we'll check collisions var asteroids_length:int = asteroids.length - 1; for (var k1:int = asteroids_length; k1 > -1;k1-- ) { var bullets_length2:int = bullets.length - 1; for(var k2:int = bullets_length2; k2 > -1;k2-- ) if (MovieClip(asteroids[k1]).hitTestObject(bullets[k2])) { stage.removeChild(bullets[k2]); bullets.splice(k2, 1); DestroyAsteroid(k1); } if (MovieClip(asteroids[k1]).hitTestObject(ship)&&ship.visible) { ship.visible = false; explosions.push(new Explosion( ship.x + ship.width / 2, ship.y + ship.height / 2, 1000, ship.width / 4)); stage.addChild(explosions[explosions.length - 1]); DestroyAsteroid(k1); } } } public function DestroyAsteroid(asteroid_hit:int):void { explosions.push(new Explosion( asteroids[asteroid_hit].x + asteroids[asteroid_hit].width / 2, asteroids[asteroid_hit].y + asteroids[asteroid_hit].height / 2, 1000, asteroids[asteroid_hit].width/4)); stage.addChild(explosions[explosions.length - 1]); //now delete the old asteroid, and add 2 new ones in it's place if there are any more sizes left var old_asteroid:Asteroid = asteroids[asteroid_hit]; //if there are more sizes to chose from if (old_asteroid.size != Asteroid.Sizes.length - 1) { var rand_dir:int = Math.floor(Math.random() * (1 + Asteroid.Directions.length - 1 )); var rand_dir2:int = rand_dir - 2; if (rand_dir - 2 < 0) rand_dir2 = rand_dir + 2; var rand_type:int = Math.floor(Math.random() * (2 )); var rand_type2:int = Math.floor(Math.random() * (2 )); //add 2 new asteroids at half the size asteroids.push(new Asteroid( old_asteroid.x, old_asteroid.y, old_asteroid.size + 1, rand_dir, rand_type)); stage.addChild(asteroids[asteroids.length - 1]); asteroids.push(new Asteroid( old_asteroid.x, old_asteroid.y, old_asteroid.size + 1, rand_dir2, rand_type2)); stage.addChild(asteroids[asteroids.length - 1]); trace("creating two new asteroids with dir = " + rand_dir + ", " + rand_dir2); } stage.removeChild(asteroids[asteroid_hit]); asteroids.splice(asteroid_hit, 1); } public function KeyDown(e:KeyboardEvent):void { if (ship.visible == false) return; if(e.keyCode==RIGHT) ship.rotation_amount = 15; if(e.keyCode==LEFT) ship.rotation_amount = -15; if(e.keyCode==UP) ship.thrust = 1; if(e.keyCode==DOWN) ship.thrust = -1; if(e.keyCode==SPACE) space_down = true; } public function KeyUp(e:KeyboardEvent):void { if(e.keyCode==RIGHT||e.keyCode==LEFT) ship.rotation_amount = 0; if(e.keyCode==UP||e.keyCode==DOWN) ship.thrust = 0; if(e.keyCode==SPACE) space_down = false; } } } |
Line 72: We create an array for the explosions.
Line 103–113: We check for any explosions that are too old and remove them, from the display and also our array.
Line 115–141: We’ll loop through all the asteroids, then looping through the bullets, use flash’s built in ‘hitTestObject’ function to check for a collision.
If so, we’ll remove the bullet, and call our function to destroy the asteroid.
After that, we check if there is a collision with the ship, and if so make it invisible, create an explosion for the ship, and call the ‘DestroyAsteroid’ function.
Line 143: This is the function we use for creating the explosion on an asteroid, removing it from the display and our array, and creating two smaller asteroids (if there are any smaller ones in our ‘sizes’ array in our asteroid class).
Line 145: First we create a new explosion, and add it to the stage to be displayed.
Line 152: We’ll create a temporary variable for the asteroid that was hit.
Line 154: Check if this is the last(smallest) size in the asteroids array, if it is not, we’ll need to create 2 smaller asteroids.
Line 185–186: Lastly, we’ll remove the asteroid that was hit from our asteroids array, and the display list.
Tutorial Demo
In the next section we’ll create a way to keep track of the lives and score, as well as create the levels, the ability to pause and restart, and a basic menu GUI.
Download the source Code and please leave me any comments or feedback you have.

