Space Shooter
So you want to create your first game in HaxeFlixel and learn about some basics about game programming?
This article is designed for you, we will assume some basic knowledge of a object orientated programming language like as3 or java.
Special thanks to Rich from Photonstorm for letting us port his as3 code and articles to HaxeFlixel.
Get your Project Setup!
Haxelib and simple command line tools are your friend. Create a new folder for this game and run the following terminal command inside it;
haxelib run flixel new -name "space_shooter"
You now have the basics setup, we will need some game assets for you space shooter. To start with you will need some images for your space ship, bullets and alien ships to shoot.
Here we are some from photonstorm.com and the as3 version of this article, feel free to use your own
;
Since we have our project setup already setup thanks to Haxelib we need to move these images into the assets folder and organise them in a subdirectory called gfx. Your folder structure should look like this;

Lets create your Space Ship class and set up the logic to let it move, fire and load your image. The code is heavily commented so take one line at a time and read on;
package;
import org.flixel.plugin.photonstorm.FlxDisplay;
import nme.Assets;
import nme.geom.Rectangle;
import nme.net.SharedObject;
import org.flixel.FlxButton;
import org.flixel.FlxG;
import org.flixel.FlxPath;
import org.flixel.FlxSave;
import org.flixel.FlxSprite;
import org.flixel.FlxState;
import org.flixel.FlxText;
import org.flixel.FlxU;
class MenuState extends FlxState
{
override public function create():Void
{
#if !neko
FlxG.bgColor = 0xff131c1b;
#else
FlxG.bgColor = {rgb: 0x131c1b, a: 0xff};
#end
FlxG.mouse.show();
//create a button with the label Start and set an on click function
var startButton = new FlxButton(0, 0, "Start", onStartClick);
//add the button to the state draw list
add(startButton);
//center align the button on the stage
FlxDisplay.screenCenter(startButton,true,true);
}
//The on click handler for the start button
private function onStartClick( ):Void
{
//Tell Flixel to change the active game state to the actual game
FlxG.switchState( new PlayState( ) );
}
override public function destroy():Void
{
super.destroy();
}
override public function update():Void
{
super.update();
}
}
The guts of this game happens in the update function. Basically HaxeFlixel runs this function almost constantly to make your game draw graphics, move your objects and do pretty much everything.
The update function is the main place where you add things to the HaxeFlixel Game Loop. You can read more about Game Loops in an interesting article here from obviam.net almost every game from space invaders to your modern FPS will be using some form of one.
Since our pixel art is so small, HaxeFlixel lets us set a zoom factor. We need to open the ProjectClass and change the ratio property. Change the code in ProjectClass.hx to the following;
package;
import nme.Lib;
import org.flixel.FlxGame;
class ProjectClass extends FlxGame
{
public function new()
{
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
var ratioX:Float = stageWidth / 640;
var ratioY:Float = stageHeight / 480;
//set the game ratio to double the size so that your ship is nice and big
var ratio:Float = Math.min(ratioX, ratioY)*2;
super(Math.floor(stageWidth / ratio), Math.floor(stageHeight / ratio), MenuState, ratio, 30, 30);
}
}
Next thing to do is to add a start button to your game's main menu. Open up MenuState.hx in the source folder and add the following.
package;
import org.flixel.plugin.photonstorm.FlxDisplay;
import nme.Assets;
import nme.geom.Rectangle;
import nme.net.SharedObject;
import org.flixel.FlxButton;
import org.flixel.FlxG;
import org.flixel.FlxPath;
import org.flixel.FlxSave;
import org.flixel.FlxSprite;
import org.flixel.FlxState;
import org.flixel.FlxText;
import org.flixel.FlxU;
class MenuState extends FlxState
{
override public function create():Void
{
#if !neko
FlxG.bgColor = 0xff131c1b;
#else
FlxG.bgColor = {rgb: 0x131c1b, a: 0xff};
#end
FlxG.mouse.show();
//create a button with the label Start and set an on click function
var startButton = new FlxButton(0, 0, "Start", onStartClick);
//add the button to the state draw list
add(startButton);
//center align the button on the stage
FlxDisplay.screenCenter(startButton,true,true);
}
//The on click handler for the start button
private function onStartClick( ):Void
{
//Tell Flixel to change the active game state to the actual game
FlxG.switchState( new PlayState( ) );
}
override public function destroy():Void
{
super.destroy();
}
override public function update():Void
{
super.update();
}
}
The comments should speak for themselves however it is calling something that does not exist PlayState. Now inside the same directory as your MenuState class create a new file called PlayState.hx.
Here is the code, we will explain the important parts below;
package ;
import org.flixel.FlxSprite;
import org.flixel.FlxG;
import org.flixel.FlxText;
import org.flixel.FlxState;
class PlayState extends FlxState
{
//this will be the text displayed to show some vital info on object pools
private var debug:FlxText;
//used to show the player instructions on inputs
private var controls:FlxText;
//create all the game state objects, overriding create is the best place
override public function create():Void
{
//initialise the game Registry
Registry.init();
//create your text
controls = new FlxText(0, 0, 360, "Press Ctrl to Fire! ---------- Press 1 / 2 / 3 to change Fire Type!");
debug = new FlxText(0, 10, 200, "");
//add your objects to the game stage to be drawn
add(Registry.stars);
add(Registry.bullets);
add(Registry.player);
add(debug);
add(controls);
}
override public function update():Void
{
//update the debug text to tell us some useful things about the bullets FlxGroup
debug.text = "Bullet Pool: " + Registry.bullets.countLiving() + "/" + Registry.bullets.members.length;
//setup the logic to change fire modes
if (FlxG.keys.justPressed("ONE"))
{
Registry.player.fireType = 1;
}
if (FlxG.keys.justPressed("TWO"))
{
Registry.player.fireType = 2;
}
if (FlxG.keys.justPressed("THREE"))
{
Registry.player.fireType = 3;
}
//dont forget to update the rest of the core state and everything in it
super.update();
}
}
As you can see this class controls a lot of what happens in your game and it's where most of the logic for your game levels will happen. If you wanted to load level maps etc you would most likely do it in your FlxState classes.
Lets add the Player class in a new file called Player.hx;
package ;
import nme.Lib;
import nme.Assets;
import org.flixel.FlxG;
import org.flixel.FlxSprite;
class Player extends FlxSprite
{
//We want to shoot bullets in a sequential delayed order over time rather than all at once
private var bulletDelay:Int = 75;
//Store the time of the last fired bullet so that we know when to shoot
private var lastFired:Int;
//the x axis movement speed
private var xSpeed:Float = 200;
//the y axis movement speed
private var ySpeed:Float = 100;
//the current fire type for the player
public var fireType:Int = 1;
public function new()
{
//Set the player location to the center and automatically load it's bitmap image :)
super(FlxG.width / 2, FlxG.height - 16,"assets/gfx/player.png");
}
override public function update():Void
{
super.update();
//Make sure the ships movement is under control
velocity.x = 0;
velocity.y = 0;
//Move the player left with the velocity value in a negative value
if (FlxG.keys.LEFT && x > 0)
{
velocity.x -= xSpeed;
}
//Move the player right with the velocity x value in a positive value
if (FlxG.keys.RIGHT && x < FlxG.width - width)
{
velocity.x += xSpeed;
}
//Move the player up with the velocity y axis value in a positive value
if (FlxG.keys.UP && y >= 100)
{
velocity.y -= ySpeed;
if (y < 100)
{
y = 100;
}
}
//Move the player up with the velocity y axis value in a negative value
if (FlxG.keys.DOWN && y < FlxG.height - height)
{
velocity.y += ySpeed;
}
//Keep the ship on the screen at all times
if (x < 0)
{
x = 0;
}
else if (x > FlxG.width - width)
{
x = FlxG.width - width;
}
//Logic to Fire!
// We dont want to fire too much at once, this lets the bulletDelay emulate an interval based on the timer and delay
if (FlxG.keys.CONTROL && Lib.getTimer() > lastFired + bulletDelay)
{
switch (fireType)
{
case 1:
// Lame Single fire
Registry.bullets.fire(Std.int(x + 5), Std.int(y) );
case 2:
// Double fire!
Registry.bullets.fire(Std.int(x), Std.int(y));
Registry.bullets.fire(Std.int(x + 10), Std.int(y));
case 3:
// Insane Quad fire!
//Notice how a 40 limit on the Bullet manager now isnt enough!! :)
Registry.bullets.fire(Std.int(x - 8), Std.int(y));
Registry.bullets.fire(Std.int(x), Std.int(y - 4));
Registry.bullets.fire(Std.int(x + 10), Std.int(y - 4));
Registry.bullets.fire(Std.int(x + 18), Std.int(y));
}
//Use the awsome nme get timer that will work on all supported runtimes
lastFired = Lib.getTimer();
}
}
}
Your folder structure should now look like this;

The main thing that that is not explained properly in the code comments above for the PlayState and Player is this mysterious Registry being called. The next article is called the Game Registry and we will explain this very handy concept. Well done so far!