Bullet Manager Part 1
There are many great games that require your player to shoot bullets and hopefully lots of them
You might be making a classic shoot-em-up or even a platformer.
This article is designed for beginners so that you can make a game with a large number of bullets and without effecting your games performance very much. Have a look at what we are making below;
To understand how and why we should 'Manage' bullets, let me introduce an invaluable programming tool for you to use;
The Object Pool
The Object Pool is a programming pattern that will let us organise our bullets into a "group". Doing this will let us use every bullet we fire in an efficient and more memory friendly way.
It will let us "recycle" bullets to shoot that are "free" instead of creating new ones.
If we did not reuse bullets, every time we wanted to shoot, we would have to create a new bullet. This might not sound so bad but when you are shooting many things the amount of bullets you are creating will grow into thousands as time goes by.
Furthermore every time a bullet is created it takes time to process and assign memory for it.
//We dont want this every time we fire var bullet:Bullet = new Bullet();
Using an Object Pool for your bullets lets us create a number of bullets to "recycle". How do we recycle them? Well we can only use ones that we are not shooting right? So we need to find this out and check if a bullet is "available". If you can imagine a bullet will be available to recycle in a few different circumstances;
- It has not been shot yet
- It has hit or killed something
- It has missed everything and went offscreen
Here you can see how an Object Pool works when we call shoot;

When using the Object Pool we ask for a bullet that is available, it will then search through the bullets and find one that is not being used like we describe.
The limitation here is the "pool size" which will be the number of bullets. This can be changed to any number of bullets for your game. The smaller pool size possible being better on memory.
See the white debug text on the example above, it tells us how many bullets are being used / how many in the pool. When you change the fire type to 3 for instance notice how the requirements for the "pool size" changes.
Meet FlxGroup
Thankfully HaxeFlixel has a built in class that you can use to make using Object Pools simple. It’s called FlxGroup. With FlxGroup you can add any custom amount of objects to a FlxGroup so its not limited to bullets.
FlxGroup gives you a wide range of methods for manipulating and using the objects for your game. You can even perform things such as group to group object collision detection.
To put this pattern into practice we must first create our Bullet Class . The Bullet class will extend FlxSprite so that we can use a simple bullet image. It has a few extra values you can play with such as damage and speed. Create your Bullet.hx class file with the following code;
package ;
import org.flixel.FlxSprite;
class Bullet extends FlxSprite
{
public var damage:Int = 1;
public var speed:Int = 300;
public function new()
{
//load your bullet image
super(0, 0,"assets/gfx/bullet.png");
// We do this so it's ready for pool availability straight away
exists = false;
}
//possibly the most important part of the game ;)
public function fire(bx:Int, by:Int):Void
{
//give the bullet its starting x and y position
x = bx;
y = by;
//the speed of the bullet being an negative y value to move up the screen
velocity.y = -speed;
//set the exists to true so that it can be drawn to the screen
exists = true;
}
override public function update():Void
{
super.update();
// Bullet off the top of the screen?
if (exists && y < -height)
{
//set the bullet exists to false so we know its available
exists = false;
}
}
}
A significant part to understand for this Bullet class is the value of 'exists'. Exists is how FlxGroup will know if a Bullet is ready to be "recycled".
The if statement in the code changes its 'exists' to false if it's y position is off the screen. This lets us use a bullet if it misses your enemy and shoots offscreen.
Now we can take a look at the Bullet Manager class so create a new file and call it BulletManager.hx. This is the class that defines our use of the Object Pool pattern in FlxGroup. It extends FlxGroup to inherit its functionality.
Here is the code for our amazing Bullet Manager;
package ;
import org.flixel.FlxGroup;
class BulletManager extends FlxGroup
{
public function new(poolSize:Int = 40)
{
super();
// Create only a limited poolSize amount of Bullets so we can reuse them
var i = 0;
while (i < poolSize) {
//create the bullet and add it to this FlxGroup
var bullet = new Bullet();
add(bullet);
i++;
}
}
// This lets us have a useful method to FIRE by using bullets available in the Object Pool
public function fire(bx:Int, by:Int):Void
{
//check if there is an available bullet
if (getFirstAvailable() != null)
{
//get an available bullet to fire and let haxe know its a Bullet type with cast
var bullet = cast ( getFirstAvailable(), Bullet );
//shoot it at the starting x and y position
bullet.fire(bx, by);
}
}
}
Yes Bullet Manager has one very important function I hope you have noticed .....fire!
This is fire function handles how we interact with the FlxGroup so we can access the "getFirstAvailble()" bullet to use. The "cast" is required to tell the Haxe compiler we know what type that it is a bullet. This lets us use the fire method inside of that bullet instance. If you do not use cast Haxe will return an error as Haxe is a Strictly Typed language.
Your Folder structure should look like this;

Are you feeling lucky?
Open your command line in your project folder and lets compile;
nme test flash
What do you see??
In the next article we will setup some alien ships to fire at!
Please use our Forums for help and leave others tips etc in the comments.
Comments
Topics - 0
Comments - 3
Member for;
5 months 2 weeks
Very cool! Thanks for the demo.
Have you tried the recycle function? I am not having much luck with it.
Topics - 25
Comments - 178
Member for;
6 months 2 weeks
Recycle works very similarly to the "fire" function above, it uses getFirstAvailable() to obtain the member that does not "exist" (has been killed). If you're having an issue using recycle you should make a post on the Help forums.
website, github, twitter
Topics - 0
Comments - 3
Member for;
5 months 2 weeks
cool, thanks, will do
Topics - 25
Comments - 178
Member for;
6 months 2 weeks
For those interested in this functionality. The Photonstorm plugins (included with HaxeFlixel) already provide this functionality, and much more. Take a look at this article for more info.
website, github, twitter