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.
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?
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.
& lt; should be changed to <, and & gt; should be changed to > (no space though between the & and the gt or lt)
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.
Done writing my algorithm, here’s a thread w/ the code and a picture.
http://www.kongregate.com/forums/5-the-arts/topics/231065-how-should-i-make-my-procedurally-generated-asteroids-look-cooler
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.