SHMUP Tutorial 8: Enemy Bullets

Welcome to part 8 of the SHMUP tutorial series! If you didn’t follow part 7 , you can download this project file to follow along! In our last tutorial we made our project more game like, but the game has nothing to challenge our players, so I thought it was about time we made our enemies fire back at us!

Let us begin with a new image!

Go ahead and save that in your images folder, and then we will embed it in our “Assets.as” file next!

[Embed(source = "Images/redbullet.png")]
public static const GRAPHIC_RED_BULLET:Class;

Great! Now that we have an image for a bullet we can jump right into this by refactoring our original “Bullet.as”

package  
{
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
 
	public class Bullet extends Entity 
	{
 
		private var moveX:Number = 0;
		private var moveY:Number = 0;
 
		public function setMovement(_x:Number = 0, _y:Number = 0):void
		{
			moveX = _x;
			moveY = _y;
		}
 
		override public function update():void
		{
			x += moveX * FP.elapsed;
			y += moveY * FP.elapsed;
			if (x > FP.camera.x + FP.width + 50 || x < FP.camera.x - 50 || y < - 50 || y > FP.height + 50) {
				destroy();
			}
		}
 
		public function destroy():void
		{
			FP.world.recycle(this);
		}
	}
}

Instead of having to copy code in multiple different bullet types, we are going to use this class to extend from for our Player and Enemy bullets. This will take a little bit of work, but in the end it will make adding new bullet types extremely easy. I’ll show you that right now, start with making a new class for our player’s bullets named “PlayerBullet.as”

package  
{
	import net.flashpunk.graphics.Spritemap;
	public class PlayerBullet extends Bullet 
	{
		private var _sprites:Spritemap;
 
		public function PlayerBullet() 
		{
			_sprites = new Spritemap(Assets.GRAPHIC_BLUE_BULLET, 10, 10);
			_sprites.add("idle", [0, 1, 2], 12, true);
			_sprites.play("idle");
			_sprites.centerOO();
			graphic = _sprites;
			type = "Bullet";
			setHitbox(6, 6, 1, 3);
			layer = GC.LAYER_BULLETS;
		}
	}
}

There is nothing new here, we just moved our old code from “Bullet.as” into this class that extends from the Bullet class. Now we have a new bullet that functions just like the old ones did. Now let’s make a new file “EnemyBullet.as”

package net 
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Spritemap;
 
	public class EnemyBullet extends Bullet 
	{
		private var _sprites:Spritemap;
 
		public function EnemyBullet() 
		{
			_sprites = new Spritemap(Assets.GRAPHIC_RED_BULLET, 10, 10);
			_sprites.add("idle", [0, 0, 0, 0, 1, 2, 3, 2, 1], 12, true);
			_sprites.play("idle");
			_sprites.centerOO();
			graphic = _sprites;
			type = "EnemyBullet";
			setHitbox(8, 8, 4, 4);
			layer = GC.LAYER_BULLETS;
		}
	}
}

This is almost identical to our player’s bullet, but this time it has a different type and graphic. Something you might not have been aware of before, is you don’t have to setup your animations for spritemaps in chronological order, and you can reuse multiple frames as many times as you want. Now that was easy to build our two different types of bullets wasn’t it?
Now we can make our enemies fire- go ahead and open up your “Enemy.as” file next find the following line of code :

private var killed:Boolean = false;

Then add this line after it.

private var shootDelay:Number;

We will be using this number to act as a timer for our enemy fire rate.
Next find your override added function and add this line of code :

shootDelay = 3;

This will make sure that every time a new enemy is created it’s timer will be reset to 3 seconds.
Now we can goto the bottom of the enemy’s update function and add in this code :

if (shootDelay > 0) shootDelay -= FP.elapsed;
else {
	var newBullet:EnemyBullet = FP.world.create(EnemyBullet) as EnemyBullet;
	newBullet.x = x - halfWidth;
	newBullet.y = y;
	newBullet.setMovement( -100, 0);
	FP.world.add(newBullet);
	shootDelay = 2;
}

This is almost identical to how our player’s firing works, so there really isn’t anything new here except we aren’t checking if our player is holding down the fire button.
With this, our enemies should now fire bullets! But they don’t actually kill our player yet.. so let’s do that next!
Finally we can open up our “Player.as” file, then you need to find this code in the update function :

if(_image.alpha >= 1) {
	if (collide("Enemy", x, y)) {
		kill();
	}
} else {
	_image.alpha += FP.elapsed;
}

and replace with this :

if(_image.alpha >= 1) {
	var enemyBullet:EnemyBullet = collide("EnemyBullet", x, y) as EnemyBullet;
	if (collide("Enemy", x, y) || enemyBullet) {
		kill();
		if (enemyBullet) {
			enemyBullet.destroy();
		}
	}
} else {
	_image.alpha += FP.elapsed;
}

This will make our player’s die when they collide with an enemy bullet, and then it will destroy the bullet that we collided into. This should look familiar since we used the same techniques for having our enemies collide with our player’s bullets.

And that brings us to updating our player’s firing mechanics. When we updated our bullets we made it so that our players fired invisible bullets that did nothing, so let’s fix that next.
Find this line of code :

var _bullet:Bullet = FP.world.create(Bullet) as Bullet;

and replace it with :

var _bullet:PlayerBullet = FP.world.create(PlayerBullet) as PlayerBullet;

Now our ship will fire the correct bullets and all is well again!

You can download a zip containing the entire project for this tutorial here .

Bookmark the permalink.

Comments are closed.

Comments are closed