Creating a Flash Asteroids Game Part 6: Creating Asteroids

Creating an Asteroids Flash game part6 - Creating The Asteroids

In the last section, we created bullets, and a method of wrapping the ship and bullets to the other side of the screen when they reach an edge of the screen.

In this section, we’ll create an asteroids class that allows us to make a variety of asteroids quickly and easily. We’ll also move them around, and wrap them on the screen.

Creating the Asteroid class

Create a new class called “Asteroid.as”, with the base class again being the GameSprite class.

Asteroid.as

package Entities
{
	import flash.display.Sprite;
	import flash.geom.Matrix;
	import flash.geom.Point;

	public class Asteroid extends GameSprite
	{

		public static const Directions:Array = [Math.PI / 4, 3 * Math.PI / 4, 5 * Math.PI / 4, 7 * Math.PI / 4];
		public static const Sizes:Array = [40, 20, 10];
		public static const Speeds:Array = [1, 3, 5];

		private var type:int;
		private var direction:Number;
		private var speed:Point;

		public function Asteroid(x:int, y:int, size:Number, direction:Number, type:int)
		{
			super(x, y, Sizes[size], Sizes[size], 0);

			this.type = type;
			this.direction = direction = Directions[direction];
			this.speed = new Point( -Speeds[size] * Math.cos(direction), -Speeds[size] * Math.sin(direction));
			trace("speed asteroid, x, y = "+(-Speeds[size] * Math.cos(direction))+", "+(-Speeds[size] * Math.sin(direction))+", direction = "+direction );

			image_sprite = new Sprite();
			image_sprite.graphics.lineStyle(1, 0xFFFFFF);
			this.type = type;

			if (type == 0)
			{
				//first lets draw the asteroid
				//they are basically circles with some craggly looking edges
				image_sprite.graphics.moveTo(0, 1 / 3 * height);
				image_sprite.graphics.lineTo(1 / 3 * width, 0);//top line
				image_sprite.graphics.lineTo(2 / 3 * width, 0);//top line
				image_sprite.graphics.lineTo(width, 1 / 3 * height); //right slanted line
				image_sprite.graphics.lineTo(width, 2 / 3 * height); //right  line
				image_sprite.graphics.lineTo(2 / 3 * width,  height); //bottom right slanted line
				image_sprite.graphics.lineTo(width / 2,  height); //bottom line
				image_sprite.graphics.lineTo(width / 2,  2 / 3 * height); //vertical bottom line
				image_sprite.graphics.lineTo(1 / 3 * width, height); //slanted bottom left line
				image_sprite.graphics.lineTo(0, 2 / 3 * height); //slanted bottom left line 2
				image_sprite.graphics.lineTo(1 / 3 * width,  height / 2); //slanted center left line 1
				image_sprite.graphics.lineTo(0, 1 / 3 * height);//back to start
			}
			else if (type == 1)
			{
				image_sprite.graphics.moveTo(0, 1 / 3 * height);
				image_sprite.graphics.lineTo(1 / 3 * width, 0);//to top left line
				image_sprite.graphics.lineTo(width / 2, 1 / 3 * height);//to center top
				image_sprite.graphics.lineTo(2 / 3 * width, 0);//to top right line
				image_sprite.graphics.lineTo(width, 1 / 3 * height);//to right top line
				image_sprite.graphics.lineTo(4 / 5 * width, height / 2);//inward right center line
				image_sprite.graphics.lineTo( width, 2 / 3 * height);//to right bottom line
				image_sprite.graphics.lineTo( 2 / 3 * width,  height);//to bottom right line
				image_sprite.graphics.lineTo( 1 / 3 * width,  height);//to bottom left line
				image_sprite.graphics.lineTo( 0,  2 / 3 * height);//to left bottom line
				image_sprite.graphics.lineTo(0, 1 / 3 * height);//back tot he start
			}
		}
		override public function Render():void
		{

			var matrix:Matrix = new Matrix();
			matrix.translate(x, y);
			Game.Renderer.draw(image_sprite, matrix);

			super.Render();
		}
		override public function Update():void
		{
			x += speed.x;
			y += speed.y;	

			if (x + width <= 0)
				x = Game.Renderer.width - width;
			else if(x >= Game.Renderer.width)
				x = 0;
				
			if (y + height <= 0)
				y = Game.Renderer.height - height;
			else if(y >= Game.Renderer.height)
				y = 0;

			super.Update();
		}
	}
}

Line 10: These are the different directions/ angles that are asteroids will travel in radians. I had picked 4 different dirrection – 45 degrees in every quadrant- so all four diaganols.
Line 11: These are the different possible sizes in pixel width/ height for all of our asteroids.
Line 12: These are the different speeds for our asteroids. It is setup so the smaller asteroid sizes correspond to the faster speeds.
Line 18: Is the constructor – in it we pass all the variables to allow us to create a variety of asteroids.
Line 31: If we pass in type 0, we will draw this pattern on the asteroids image sprite.
Line 31: If we pass in type 1, this alternative asteroid pattern onto the sprite.

Next, we need to update the Game class to spawn the asteroids.

Game.as

package 
{
	import Entities.Asteroid;
	import Entities.Bullet;
	import Entities.Ship;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;

	public class Game
	{
		public var bitmap:Bitmap;
		public static var Renderer:BitmapData;
		
		private var ship:Ship
		
		private var keys_down:Array
		
		private const LEFT:int = 37;
		private const UP:int = 38;
		private const RIGHT:int = 39;
		private const DOWN:int = 40;
		private const SPACE:int = 32;	
		
		public static var current_time:Number;
		private var bullets:Array;
		private var firing_delay:Number;
		private var last_fired:Number;
		private var bullets_max_life:Number;
		
		private var asteroids:Array;
		

		public function Game(stageWidth:int, stageHeight:int)
		{
			trace("Game created");
			Renderer = new BitmapData(stageWidth, stageHeight, false, 0x000000);
			bitmap = new Bitmap(Renderer);

			ship = new Ship(Renderer.width / 2 - 6, Renderer.height / 2 - 10, 10, 18);
			//ship = new Ship(Renderer.width / 2 - 6, Renderer.height / 2 - 10, 50, 100);
			keys_down = new Array();
			bullets = new Array();
			firing_delay = 200;
			last_fired = 0;
			bullets_max_life = 1000;
			
			asteroids = new Array();
			//setup four first asteroids
			asteroids.push(new Asteroid(Renderer.width / 5, 2 * Renderer.height / 3, 0, 0, 0));
			asteroids.push(new Asteroid(Renderer.width / 5, Renderer.height / 4, 0, 1, 0));
			
			asteroids.push(new Asteroid(2*Renderer.width / 3, 1 * Renderer.height / 3, 0, 2, 0));
			asteroids.push(new Asteroid(2*Renderer.width / 3, 5 * Renderer.height / 5, 0, 3, 0));
			

		}
		public function Render():void
		{
			Renderer.lock();
			Renderer.fillRect(new Rectangle(0, 0, Renderer.width, Renderer.height), 0x000000);

			ship.Render();
			for (var i:int = 0; i < bullets.length; i++)
				bullets[i].Render();
				
			for (var j:int = 0; j < asteroids.length; j++)
				asteroids[j].Render();


			Renderer.unlock();
		}

		public function Update():void
		{
			current_time = getTimer();
			
			if (CheckKeyDown(LEFT))			
				ship.RotateLeft();
			
			if (CheckKeyDown(RIGHT))
				ship.RotateRight();
				
			if (CheckKeyDown(UP))
				ship.Thrust(1);
			if (CheckKeyDown(DOWN))
				ship.Thrust( -1);
				
			if (CheckKeyDown(SPACE) && current_time-last_fired > firing_delay)
			{
				var x:int = 0 * Math.cos(ship.angle) + ship.rotate_offset.y * Math.sin(ship.angle)+ship.x+ship.rotate_offset.x;
				var y:int = 0 * Math.sin(ship.angle) - ship.rotate_offset.y * Math.cos(ship.angle)+ship.y+ship.rotate_offset.y;
				
				bullets.push(new Bullet(x, y, current_time, ship.angle));
				last_fired = current_time;
			}
				
			ship.Update();

			var bullets_to_delete:Array = new Array();
			for (var i:int = 0; i < bullets.length; i++)
			{
				bullets[i].Update();
				if (current_time-bullets[i].life > bullets_max_life)
					bullets_to_delete.push(i);
			}
			for (var j:int = 0; j < bullets_to_delete.length;j++ )
			{
				bullets.splice(bullets_to_delete[j], 1);
			}		
			for (var k:int = 0; k < asteroids.length;k++ )
				asteroids[k].Update();
		}
		
		public function KeyUp(e:KeyboardEvent):void
		{
			//position of key in the array
			var key_pos:int = -1;
			for (var i:int = 0; i < keys_down.length; i++)
				if (e.keyCode == keys_down[i])
				{
					//the key is found/was pressed before, so store the position
					key_pos = i;
					break;
				}
			//remove the keycode from keys_down if found 
			if(key_pos!=-1)
				keys_down.splice(key_pos, 1);			
		}
		
		public function KeyDown(e:KeyboardEvent):void
		{
			//check to see if the key that is being pressed is already in the array of pressed keys
			var key_down:Boolean = false;
			for (var i:int = 0; i < keys_down.length; i++)
				if (keys_down[i] == e.keyCode)
					key_down = true;
			
			//add the key to the array of pressed keys if it wasn't already in there
			if (!key_down)
				keys_down.push(e.keyCode);			
		}
		
		public function CheckKeyDown(keycode:int):Boolean
		{
			var answer:Boolean = false;
			for (var i:int = 0; i < keys_down.length; i++)
				if (keys_down[i] == keycode)
				{
					answer = true;
					break;
				}
			return answer;
		}	
	}
}

Tutorial Demo

In the next section we’ll create a way to detect collisions, and create explosions!

Download the source Code and please leave me any comments or feedback you have.

Other Articles in this Series

Bookmark the permalink.

9 Comments

  1. Okay, so in the Game.as there are 22 syntax errors I’m getting on lines, 65 68 89 101 104 107 111 119 135 and 147. Majority of them are “expecting rightparen before semicolon” or “expecting semicolon before rightparen” these lines that are using more than 1 semicolon, such as 65 “for (var i:int = 0; i < bullets.length; i++)” it has a problem with the last semicolon and the ).

    I figured I typed something wrong, so I cleared the Game.as and copied your code and pasted it, same errors. Any thoughts?

  2. Ah- stupid wordpress. at line 65, if changed the less than sign into “<“, and probably changed the greater than signs as well (to proper html, which it shouldn’t be).

    If you search for those and change them from < to > it should fix the code. I’ll also update the code that shows in html here to hopefully fix it.
    (the download link will give you the original code as well)

    Sorry about that, it happened on some of the other parts, but I had though that it had all been fixed.

  3. & lt; should be changed to < , and & gt; should be changed to > (no space though between the & and the gt or lt)

  4. Hello. I wrote a procedural generation algorithm(that is the correct term, right?) for the asteroids!

    for (var i:int = thelevel2 + 3; i >= 0; i–)
    {
    asteroids.push(new asteroid(
    archetect.width / (Math.floor(1 + (Math.random() * 5))),
    archetect.height / (Math.floor(1 + (Math.random() * 5))),
    0,
    Math.floor(Math.random() * 4),
    Math.floor(Math.random() * 2))
    );
    }

    • Cool, you’ll have to show your asteroids when you’re finished!

      • Sorry, I was unclear. I did not mean the asteroids’ sprites, i meant their stats, as depicted by my code. Now that you mention it though, randomly generating the asteroid sprites sounds cool. I think I’ll try it out.

        • Now that I think about it, would it be possible to increase asteroid variety by flipping the 2 sprites we’ve already coded in? 2(number of asteroid sprites) * 2(whether or not they are flipped horizontally) * 2(whether or not they are flipped vertically) = 8, 6 more sprites than before.

    • Cool! I checked it out, and your new game looks like an awesome improvement over straight asteroids!

      Great job, I’d like to see what games people have went on to create 😀

      Need to create some more tutorials soon- been too long, and I’d like to get a game development group going.

Leave a Reply

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