Featured, Flash, Games, Tutorials
comments 87

Flixel 2 Tutorial [Flash, Tutorials, Games]

flixeltutorial00

In this tutorial, I’ll explain how to develop a very simple Defender-style game using the open-source Flixel 2 game library for Flash. Flixel was written by Adam Saltsman and extracted from a couple of his own Flash games, including Gravity Hook, Fathom and Canabalt. There is also an iPhone version lurking around the corner, which will make Flixel even more useful.

Flixel is an AS3-only framework which means that we don’t need Adobe Flash CS4 at all. No movieclips, no timeline, no library and no high price tag. Instead, we will do everything with pure code and bitmap spritesheets.

Game demo:

Setting up the project

Before we start, you need to setup your working environment so you can compile AS3-only projects into SWF files using the free Flex SDK. For this tutorial I have used Flex SDK 4.0. If you work on a Mac I recommend using TextMate for editing the source code. Have a look at this tutorial for how to set it up for AS3 projects. If you work on Windows FlashDevelop is a popular choice and completely free. The Flixel wiki has a good tutorial on how to setup FlashDevelop for Flixel.

Next, download version 2.32 of the Flixel library from GitHub. Since new versions of Flixel are frequently released version 2.32 might not be latest one, but we can be sure the tutorial will work with this version of Flixel.

Now let’s set up the basic project directory structure. Create a project folder that contains the TextMate or FlashDevelop project file, a folder for all graphic and sound assets, a folder for all source files with the Main.as file at the root and a bin folder for the compiled SWF. Move the org folder from the Flixel library into the src folder. Create the subfolders de/pixelate/flixelprimer for the actual source files of the game.

You can find the complete source code for this tutorial on GitHub including the graphic and sound assets we will use for the tutorial.

Main.as will be the entry point for our game. Whenever it runs, it will execute the code in this class first. Make sure that you point the compiler to the Main.as file. (See links to the tutorials above on how to do this in TextMate or FlashDevelop.) When using Flixel we make the Main class a subclass of FlxGame, which is the heart of every Flixel game. The Main class imports the ActionScript files we need, sets up the screen size to 640×480 and starts the game with the PlayState.

package {
import org.flixel.*;
import de.pixelate.flixelprimer.*;

[SWF(width="640", height="480", backgroundColor="#ABCC7D")]
[Frame(factoryClass="Preloader")]

public class Main extends FlxGame
{
public function Main():void
{
super(640, 480, PlayState, 1);
}
}
}

The main class also points to the Preloader class, which will show a nice 8-bit style preloader bar when loading the game in the browser. The class looks like this:

package
{
import org.flixel.FlxPreloader;

public class Preloader extends FlxPreloader
{
public function Preloader():void
{
className = "Main";
super();
}
}
}

A Flixel game usually consists of different states which subclass FlxState. A common usage would be to have a state for the menu screen, one for the actual game and one for the highscore screen. In our case we will only use one state to keep things simple. Let’s add the scaffold for the play state. The create function will be called once PlayState is created by the main class. The update function is the main loop of the game which will be called every frame.

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class PlayState extends FlxState
{
override public function create():void
{
super.create();
}

override public function update():void
{
super.update();
}
}
}

Adding the player sprite and controls

Now that we have a good scaffold for the game, let’s add a space ship for the player. Create a new class in src/de/pixelate/flixelprimer called Ship.as:

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class Ship extends FlxSprite
{
[Embed(source="../../../../assets/png/Ship.png")]
private var ImgShip:Class;

public function Ship():void
{
super(50, 50, ImgShip);
}

override public function update():void
{
velocity.x = 0;
velocity.y = 0;

if(FlxG.keys.LEFT)
{
velocity.x = -250;
}
else if(FlxG.keys.RIGHT)
{
velocity.x = 250;
}

if(FlxG.keys.UP)
{
velocity.y = -250;
}
else if(FlxG.keys.DOWN)
{
velocity.y = 250;
}

super.update();
}
}
}

FlxSprite is the main game object class in Flixel and handles basic physics and animation. The Ship class extends FlxSprite, draws the sprite at position x 50 and y 50 and sets the bitmap graphic for the ship which resides in the assets folder. The player controls are handled in the update function which is called by Flixel every frame. First the velocity is set back to zero. Then we check if the player is pressing the arrow keys and change the velocity accordingly. The super.update() call takes care of changing the position of the ship based on the current velocity.

Now we have to add the ship to the game stage. Add the following code to the create function in PlayState.as and declare _ship as a private variable above the function. We also set the background color of the game state to a nice monochrome green.

private var _ship: Ship;

override public function create():void
{
bgColor = 0xFFABCC7D;

_ship = new Ship();
add(_ship);

super.create();
}

Now compile the project and start the SWF in the Flash Player. Move the ship around with the arrow keys. The player input works well but the ship can move outside the screen. Let’s fix that. Add the following code into the update function in Ship.as where we make sure that the position of the ship is always within the screen dimensions. We also add a padding of 16 pixels to the if-condition to make it look nicer. Make sure to insert the code after the super.update() call.

if(x > FlxG.width-width-16)
{
x = FlxG.width-width-16;
}
else if(x < 16)
{
x = 16;
}

if(y > FlxG.height-height-16)
{
y = FlxG.height-height-16;
}
else if(y < 16)
{
y = 16;
}

Adding enemies

Next, let’s add some enemies. Create the file Alien.as inside src/de/pixelate/flixelprimer. The Alien class takes x and y as arguments in the constructor so we can easily position the sprite when creating it. We set the horizontal velocity to -200 which makes the alien move from right to left at a constant speed. In the update function we use a cosine function to move the alien up and down in a wave motion.

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class Alien extends FlxSprite
{
[Embed(source="../../../../assets/png/Alien.png")]
private var ImgAlien:Class;

public function Alien(x: Number, y: Number):void
{
super(x, y, ImgAlien);
velocity.x = -200;
}

override public function update():void
{
velocity.y = Math.cos(x / 50) * 50;
super.update();
}
}
}

To spawn the aliens, we need to add some more code to the PlayState. First we add a FlxGroup for the alien sprites, a logical container which helps us to organize the collision detection between the player ship and aliens. Second we add a spawn timer which controls the interval when a new alien is spawned. The interval starts at 2.5 seconds and slowly becomes faster until it reaches it’s maximum of spawning a new alien every tenth second. Finally we add a function for spawning an alien at a random position at the right border of the screen.

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class PlayState extends FlxState
{
private var _ship: Ship;
private var _aliens: FlxGroup;
private var _spawnTimer: Number;
private var _spawnInterval: Number = 2.5;

override public function create():void
{
bgColor = 0x0ABCC7D;

_ship = new Ship();
add(_ship);

_aliens = new FlxGroup();
add(_aliens);

resetSpawnTimer();

super.create();
}

override public function update():void
{
_spawnTimer -= FlxG.elapsed;

if(_spawnTimer < 0)
{
spawnAlien();
resetSpawnTimer();
}

super.update();
}

private function spawnAlien():void
{
var x: Number = FlxG.width;
var y: Number = Math.random() * (FlxG.height - 100) + 50;
_aliens.add(new Alien(x, y));
}

private function resetSpawnTimer():void
{
_spawnTimer = _spawnInterval;
_spawnInterval *= 0.95;
if(_spawnInterval < 0.1)
{
_spawnInterval = 0.1;
}
}
}
}

Adding bullets

Now let’s add bullets so the player can shoot to fight the aliens. Create a new class in src/de/pixelate/flixelprimer called Bullet.as. Nothing fancy here, except that we don’t use a bitmap graphic, but draw the bullet directly in the createGraphic() call.

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class Bullet extends FlxSprite
{
public function Bullet(x: Number, y: Number):void
{
super(x, y);
createGraphic(16, 4, 0xFF597137);
velocity.x = 1000;
}
}
}

As with the aliens we add a FlxGroup for the bullets and a spawn function as well. In the update function we check if the player just pressed the space key and fire a bullet if that is the case.

package de.pixelate.flixelprimer
{
import org.flixel.*;

public class PlayState extends FlxState
{
private var _ship: Ship;
private var _aliens: FlxGroup;
private var _bullets: FlxGroup;
private var _spawnTimer: Number;
private var _spawnInterval: Number = 2.5;

override public function create():void
{
bgColor = 0x0ABCC7D;

_ship = new Ship();
add(_ship);

_aliens = new FlxGroup();
add(_aliens);

_bullets = new FlxGroup();
add(_bullets);

resetSpawnTimer();

super.create();
}

override public function update():void
{
if(FlxG.keys.justPressed("SPACE") && _ship.dead == false)
{
spawnBullet(_ship.getBulletSpawnPosition());
}

_spawnTimer -= FlxG.elapsed;

if(_spawnTimer < 0)
{
spawnAlien();
resetSpawnTimer();
}

super.update();
}

private function spawnBullet(p: FlxPoint):void
{
var bullet: Bullet = new Bullet(p.x, p.y);
_bullets.add(bullet);
}

// ...
}
}

Note that we also added a new function to Ship.as to get the correct spawn position for the bullet from the player’s ship:

public function getBulletSpawnPosition():FlxPoint
{
var p: FlxPoint = new FlxPoint(x + 36, y + 12);
return p;
}

Adding collision detection

The only thing missing to make our game playable is collision detection. We handle the collision in the beginning of the update function of PlayState. The first call checks if any sprite in the aliens group overlaps with any bullet sprite and calls the overlapAlienBullet callback if so. The second call checks for collisions between the aliens and the ship sprite.

[sourcecode language=”as3″]FlxU.overlap(_aliens, _bullets, overlapAlienBullet);
FlxU.overlap(_aliens, _ship, overlapAlienShip);[/sourcecode]

In the callback functions we define what happens in case of a collision. When an alien sprite gets hit by a bullet, we destroy both the alien and the bullet sprite, increase the score counter and display the updated score on the screen. When the ship gets hit by an alien we also let the screen rumble a bit using the quake function and display a game over message.

private function overlapAlienBullet(alien: Alien, bullet: Bullet):void
{
alien.kill();
bullet.kill();
FlxG.score += 1;
_scoreText.text = FlxG.score.toString();
}

private function overlapAlienShip(alien: Alien, ship: Ship):void
{
ship.kill();
alien.kill();
FlxG.quake.start(0.02);

_gameOverText = new FlxText(0, FlxG.height / 2, FlxG.width,
"GAME OVER\nPRESS ENTER TO PLAY AGAIN");
_gameOverText.setFormat(null, 16, 0xFF597137, "center");
add(_gameOverText);
}

We also need to initialize the text fields. Add a private variable declaration for the text fields in PlayState:

private var _scoreText: FlxText;
private var _gameOverText: FlxText;

To allow the player to restart the game on game over we add the following code to the update function in the PlayState:

if(FlxG.keys.ENTER && _ship.dead)
{
FlxG.state = new PlayState();
}

Create the score text field in the create function in PlayState and set the FlxG.score variable to zero.

FlxG.score = 0;
_scoreText = new FlxText(10, 8, 200, "0");
_scoreText.setFormat(null, 32, 0xFF597137, "left");
add(_scoreText);

Adding sounds

The game is fully playable now. Let’s add some sounds to give the player a better feedback of the action. Define all references to the sound files in the header of PlayState.

public class PlayState extends FlxState
{
[Embed(source="../../../../assets/mp3/ExplosionShip.mp3")]
private var SoundExplosionShip:Class;
[Embed(source="../../../../assets/mp3/ExplosionAlien.mp3")]
private var SoundExplosionAlien:Class;
[Embed(source="../../../../assets/mp3/Bullet.mp3")]
private var SoundBullet:Class;

// ...
}

We call the FlxG.play function to play the sounds in the according situations.

// In spawnBullet()
FlxG.play(SoundBullet);

// In overlapAlienBullet()
FlxG.play(SoundExplosionAlien);

// In overlapAlienShip()
FlxG.play(SoundExplosionShip);

Adding explosions

Finally we add some particle explosions when the ship or an alien is destroyed using the FlxEmitter class. We want to use the same explosion for the ship and the aliens so we move the explosion code into a reusable function.

private function createEmitter():FlxEmitter
{
var emitter:FlxEmitter = new FlxEmitter();
emitter.delay = 1;
emitter.gravity = 0;
emitter.maxRotation = 0;
emitter.setXSpeed(-500, 500);
emitter.setYSpeed(-500, 500);
var particles: int = 10;
for(var i: int = 0; i < particles; i++)
{
var particle:FlxSprite = new FlxSprite();
particle.createGraphic(2, 2, 0xFF597137);
particle.exists = false;
emitter.add(particle);
}
emitter.start();
add(emitter);
return emitter;
}

In the collision callback functions we create the emitter for the explosion and place it at the position of the ship or alien using emitter.at().

// In overlapAlienBullet()
var emitter:FlxEmitter = createEmitter();
emitter.at(alien);

// In overlapAlienShip()
var emitter:FlxEmitter = createEmitter();
emitter.at(ship);

Now you have a simple game in Flixel that should help you getting started building your own ideas. If you have any questions, leave a comment or have a look at the Flixel forums and the wiki.

  • Zever

    Very nice explanation ! Was a perfect & easy to understand introduction to Flixel. Keep up the good work !

  • http://www.pixelate.de Pixelate

    @Franth: I’d suggest to add another FlxGroup for the alien bullets to PlayState (e.g. _alienBullets). This way it will be much easier to do the collision detection. “Add (_bullets)” inside Alien.Update() does not work, because the Alien class does not have a property called _bullets.

  • http://www.pixelate.de Pixelate

    @Zever: Thanks! I’m glad you found it helpful.

  • Brotha_C

    Why do you put flixel in the src folder?
    Other tutorials I’ve seen just say:
    import flixel.*;
    And that way you import everything right?
    One more question- this will work with flixel 2.35 right?

    Thank you for still replying to people’s questions. I have seen it where this just stops after a while.

  • http://www.pixelate.de Pixelate

    @Brotha_C: You need to put the Flixel library somewhere where the compiler can find it. The easiest way is to put it in the same folder as the rest of your project source code. If you do “import flixel.*” it will import all Flixel classes, but the import statement itself does not tell the compiler where to look for them.

    I have not tested the tutorial with Flixel 2.35, but I’d assume it works.

  • Brotha_C

    @ Pixelate
    Okay thanks.
    I have gone up to the “adding aliens” section and it has worked fine so far.
    Thanks for the help!

  • Franth

    @Pixelate: Thanks for the advice. I’ve already modified the code and it works just perfect! I had to check one by one the position of the aliens in _aliens, but it was easier than I thought ;)

  • http://www.pixelate.de Pixelate

    @Franth: Great you got it working. ;)

  • Timbaz

    hey yall, first of all nice tutorial here! i really appreciate your work, only i have some errors in the playstate file.
    1180: Call to a possibly undefined method resetSpawnTimer.
    1180: Call to a possibly undefined method spawnAlien.

    errors show that lines:
    override public function create():void
    {
    bgColor = 0x0ABCC7D;

    _ship = new Ship();
    add(_ship);

    _aliens = new FlxGroup();
    add(_aliens);

    _bullets = new FlxGroup();
    add(_bullets);

    resetSpawnTimer();

    and this part of the code:
    _spawnTimer -= FlxG.elapsed;

    if(_spawnTimer < 0)
    {
    spawnAlien();
    resetSpawnTimer();
    }

    could someone help me with this problem, i dont know what i did wrong atm…

  • http://www.pixelate.de Pixelate

    @Timbaz: Try to download the complete source code from GitHub (see link in the tutorial) and compare if you maybe have missed to write some of the needed functions.

  • http://www.facebook.com/people/Okeowo-Omololu-Remi/542355222 Okeowo Omololu Remi

    At Long Last i can now try out Flixel God Knows how frustrated i was not knowing what Class/Object does what?thanks mate

  • Mc

    Thanks for the tutorial!
    Just 1 question: the bullets that don’t hit the enemies keep going for ever? should we destroy them when they get offScreen? as well with the enemies you dont shoot,… they’re not destroyed anywhere and keep using memory, or am i missing something?
    Maybe we can add something like
    if (onScreen==false) { this.kill();}
    in the update function in Bullet.as/Alien.as ?

  • k1tsune

    I would like to thanks too :) Good initiation on flixel!

    Bt the way, I like the Mc question. It was mine too. Before implemented the collision, i just left the aliens creation to see how it behaves, and a lot of ‘em were created. I checked memory to make sure memory usage wasn’t increasing. So it wasn’t. So, I concluded there are some kind of control over the items that are not being used. Is it correct??

    Thanks again

  • k1tsune

    Hey Timbaz,

    You have to implement the functions resetSpawnTimer and spawnAlien functions on PlayState class :) Do it and everything is gonna be alright!

  • k1tsune

    Ok, just read Pinchbeck question and understood now that every item created (enemy or bullet) aren’t destroyed after leaving screen. Good to know :)

  • http://www.pixelate.de Pixelate

    I wanted to keep the code as simple as possible, which is why the objects are not deleted when going off screen. Doing that is definitely best practice, but you can see that Flixel is really performant even if you don’t optimize your code.

  • samu

    I’ve tried building this using flex 4.5 and textmate and all I see when I run it is the flixel “f” splash.
    Ideas?

  • http://www.pixelate.de Pixelate

    @samu: Are you using version 2.32 of Flixel?

  • samu

    @andreaszecher:disqus Not at first, but then I switched after I had an issue with extending the preloader class. When it still wouldn’t work, I decided to try an older version of the Flex SDK with the older version of Flixel and it all finally worked.

    Thanks for the nice tutorial.

  • Robert Wildling

    For those of you who use a neer version of Flixel, watch out for some changes. For example, some functions that were in FlxU, have now been moved to FlxG like the random-function (it used to be FlxU.random() and is now FlxG.random…). – Changing state is now something like FlxG.switchState(new MenuState()); and no longer FlxG.state = MenuState. And it is no longer called FlxSprite.createGraphic(), but FlxSprite.makeGraphic….

    I actually didn’t find any documentation on what was changed where, but going to http://flixel.org/docs/ and using the “Index” link in the top right corner can still help quite a bit.

    @Andreas: great and very helpful tutorial, thank you! I wonder if you plan to update it to a newer version since the comments are still going here. Seems to be a very popular post…

  • http://www.pixelate.de Pixelate

    @google-f425f00f71e0a8a7bab3bfe61b64e448:disqus I’m glad you found the tutorial helpful. I’d want to update the tutorial at some time – if time allows that is.

  • dewey

    Hi,

    Does the FlxGroup take care of object pooling? Or is that something I should be worrying about myself?

    –d

  • http://www.pixelate.de Pixelate

    Yes, FlxGroup does the object pooling for you.

  • dewey

    Appreciate the response! A couple other small things:

    I’m using the latest Flixel “master” build:

    – player.dead appears to now be !player.alive
    – FlxU.state doesn’t really work as it is now read-only… I have FlxG.resetState in there at the moment, but have no idea whether or not that’s correct.
    – FlxG.quake doesn’t seem to exist any more… do you know what the newest function for quaking is?

    Thanks!

    –d

  • dewey

    Appreciate the response! A couple other small things:

    I’m using the latest Flixel “master” build:

    – player.dead appears to now be !player.alive
    – FlxU.state doesn’t really work as it is now read-only… I have FlxG.resetState in there at the moment, but have no idea whether or not that’s correct.
    – FlxG.quake doesn’t seem to exist any more… do you know what the newest function for quaking is?

    Thanks!

    –d

  • Adam

    “- FlxG.quake doesn’t seem to exist any more… do you know what the newest function for quaking is?”

    FlxG.shake seems to be it.

  • Barrow

    Thanks dewey, was having a hard time trying to figure out the “dead” and “state” thing myself.

    As for quake, I’m not sure what it used to do, but it looks like the new syntax is “FlxG.shake(.02);”

  • confused

    Now if only there was a way for me to find out what all of this meant. I guess I’ll go do some beginner tutorials and try again.

  • Chris

    Thanks Andreas, this tutorial was great.  I learned a lot about Flixel by following it.
    I did this last night using the version of Flixel you used.  I did it again tonight (23/08/2011) using the current Master version of Flixel, 2.55. Here’s the changes I had to make to make it work with the newer version of Flixel.  I’m hoping it’ll help out anyone else that’s using a newer version of Flixel:

    First, using mxmlc as my compiler I was getting an error of “VerifyError: Error #1014: Class mx.core::SpriteAsset could not be found.” This has nothing to do with which version of Flixel is being used. It was fixed by adding the argument “-static-link-runtime-shared-libraries=true” when compiling.

    changed “bgColor” to “FlxG.bgColor”
    changed “_ship.dead == false” to “_ship.alive”
    changed “createGraphic” to “makeGraphic”
    changed “_ship.dead” to “!_ship.alive”
    changed “FlxG.quake.start” to “FlxG.shake”
    changed “FlxU.overlap” to “FlxG.overlap” I think “FlxG.collision” would work too.
    changed “FlxG.state = new PlayState();” to FlxG.resetState();”
    changed “emitter.delay” to “emitter.lifespan”

    I had what seemed to be an odd issue after those changes.  The particles were little Flex logos as opposed to the particles in your original example.  This may not be the best way to do this, but here’s how I fixed it based off reading the docs for Flixel v2.55:

    I removed the for Loop in createEmitter() in Playstate.as. (Starts as for (var i:int; i < particles; i ++))
    Then I added these two lines in Playstate.as's header by where you embed the sound files:
    [code]
    [Embed(source="../assets/png/particle.png")]
    private var _imgParticle:Class;
    [/code]

    I added this line where the for loop used to be in createEmitter():
    [code]
    emitter.makeParticles(_imgParticle, 10);
    [/code]

    And I of course had to make the particle png, I just used KolourPaint to make a 4px X 4px png filled with 0x597137 and named it particle.png in my assets/png folder.  To save anyone else the trouble if this is indeed the correct way to do this with Flixel now the image of the particle should show up as my avatar for this comment.

    Again, thanks for the great tutorial Andreas.  Prior to this I had been banging my head against the wall trying to learn how to make a game in AS3.  But this has shown me just how easy and great Flixel is so I'm going to play around with Flixel while I'm learning more of the complex issues with making a game from scratch.
    -Chris

  • Chris

    Guess the particle image showed up as an attachment and not an avatar.

  • http://www.pixelate.de Pixelate

    @Chris, thanks for sharing your fixes for the tutorial!

  • xinkuzi

    Awesome tutorial, thanks for sharing! Unfortunately I have been running into some errors. I solved the first few problems I had (noob problems) but now I’m getting this when I try to “test project” in FlashDevelop, or run the compiled swf:

    [Fault] exception, information=ArgumentError: Error #1063: Argument count mismatch on org.flixel::FlxGame(). Expected 3, got 0.

    Any idea? Thanks!

  • Amir

    Thank you very much for comment. Without you, I could not have succeeded.
    Regards,
    Amir

  • Guest

     Ruined formating, sadly…

  • Pingback: Flex / ActionScript 3 / Flixel on Mac « Chasing The Metaphysical Express()

  • Pingback: Flixel Hello World Basic Shooter Game in Flash and Flex | Lon Hosford()

  • blizzkreme

    Thanks for this infor bro. It’s worth a try. By the way, can I collaborate it with Big Game Hunter, the one found in http://bit.ly/1hubcQm?