HF Breakout 1 - Anatomy of a Project
Welcome to another HaxeFlixel tutorial! This time we’ll learn how to create a Breakout game from scratch.
This tutorial is meant for beginners, so we’ll take our time and go through some of the basics of HaxeFlixel. You’ll need to have HaxeFlixel installed and set up before you start, so head on over to the official website and follow the instructions there!
Alright! Now let’s create a project from the command line and call it HFBreakout, by doing this:
flixel tpl -n "HFBreakout"
Open the project up in your IDE of choice. Like the HF website, I highly recommend VSCode. You can find infos on how to set it up and how to use it on the website as well. Now let’s go and make a Breakout clone!
First, let’s get some basics out of the way and take a look at how a HaxeFlixel project is put together. Inside the
source folder of your project folder you’ll find the file
Main.hx. This serves as the backbone of the entire project and is the entry point for the game. Open the file up in your IDE.
As you can see, there’s not a lot going on in there; there’s just the line
addChild(new FlxGame(0, 0, PlayState));. This line creates a new
FlxGame instance and adds it to the OpenFL stage. That might sound weird, but HF is actually based on OpenFL. All the HF code will be contained inside
FlxGame, and there should only ever be one instance of it.
The arguments of the function call set the size of the game window and define the starting state. We’ll get to both of those aspects in a second.
You might wonder why we’re setting the size of
FlxGame to be
0. This tells HF to use the sizes defined in the
project.xml file, which contains a list of settings and definitions for the project. Open it up; you’ll find it in the root folder of your project.
There’s a lot going on in here, but we’re interested in the following line:
<!--These window settings apply to all targets--> <window width="640" height="480" fps="60" background="#000000" hardware="true" vsync="false" />
Here, the size of the window is set to 640x480. And that is an important distinction: We’re only defining the size of the window here, not the size of the game. The size of the game is defined by the arguments we pass into the constructor of
FlxGame. In our case, we passed in
0,0, which tells HF to make the game the same size as the window — 640x480.
You might wonder why we’d want to make the window a different size than the game. Imagine you want to make a really low-resolution pixel game. In that case you might use a game size of 320x160 or something like that to keep everything nice and chunky. However, on modern screens, a window of size 320x160 is tiny. You wouldn’t be able to see anything. So, in such a case, you’d do
addChild(new FlxGame(320, 160, PlayState)) but set the
project.xml to something bigger, like 640x320 or 960x480. HaxeFlixel will then scale up the game to fill the window. That way you can work with your low resolution, but players will still be able to see what’s going on!
For our project we’ll make the game and window size the same (which is the default for a new HF project).
Main.hx we create a
FlxGame object of size 640x480. Then it starts the
PlayState. This state is defined in the file
PlayState.hx, which you can find in the
source folder. Open it up!
As you can see, it defines a class called
PlayState that extends
FlxState. States are the main building block of games. You can use them to organize your game code. A simple game like Galaga (or indeed Breakout) can be done in a single state, but more complex games should be split across multiple states; one for the main menu, one for gameplay, one for cutscenes, one for the inventory screen… Basically, if a part of your game has a completely different functionality than other parts, you should probably stick it into its own
FlxState. As we’re only making a simple game, we’ll put all our code inside the
You can see that two functions are pre-defined in
PlayState: We have
create function is called at the beginning of the state, and is only called once. In here you do everything you need to set up the state: Load graphics, initialize systems, and so on. The
update function contains the main game loop. It is called automatically every frame, so here is where the action happens. In
update you’ll poll for inputs, move sprites, handle collisions…all the fun stuff.
That’s it for the basic overview of a HF project! One final word before we actually start coding though: I recommend compiling the game for the
HashLink target during this tutorial. The code should work for any target, but HashLink is great for testing as it’s quick and rather similar to targeting a native platform (Windows, Linux…).
Now let’s actually code something and make things happen!
One of the most important classes in HaxeFlixel is
FlxSprite. This class defines an object that has a graphic, a position, velocity and many other properties. Simply put: If it moves, it’s probably a
FlxSprite. We’ll use these sprites for almost everything in our game.
Let’s create the paddle to see how it works. First, download the graphic for the paddle from the link below:
Extract the image file and put it into the
assets/images folder of your project. Then, in the PlayState, create a new variable at the top of the class (not inside of
var paddle:FlxSprite = null;
This variable will hold our paddle. Then, in
create, after the call to
super.create(), add the lines:
paddle = new FlxSprite(0, 0, "assets/images/paddle.png"); add(paddle);
Compile the game and you’ll see the paddle sitting in the top-left corner of the screen!
We created our
FlxSprite at position
0,0. Since we use a simple static graphic, we can just pass it into the constructor. And that’s all you need to make a
FlxSprite! However, we also have to
add the sprite to the state. If you don’t add it, HaxeFlixel will basically act as if it doesn’t exist and it therefore won’t appear on screen. So don’t forget to add your sprites!
The paddle isn’t doing us a lot of good up there in the corner though, so let’s try putting it somewhere else. We could of course simply pass in different coordinates into the constructor, but there is another way to position a
FlxSprite: The method
setPosition…well, it sets the position of the sprite. This function takes two arguments: The desired x and y coordinates. So, after creating the paddle sprite, do this:
paddle.setPosition(FlxG.width / 2 - paddle.width / 2, FlxG.height - 64);
Note: You can add this line either before or after
add(paddle). It doesn’t really make a difference in this case!
This will set the paddle’s x-position to
FlxG.width / 2 - paddle.width / 2 and the y-position to
FlxG.height - 64. But what’s
FlxG and the other stuff?
FlxG is a very useful global helper class that handles general functionality. In our case we get the
height properties, which contain the width and height of our game (as defined in the
FlxGame constructor). So
FlxG.width / 2 is the horizontal center of screen. We then shift the paddle’s position left by half its
width, to properly center it.
width is a property of
FlxSprite, along with
By the way: In HaxeFlixel, the top edge of screen has the y-value 0, while the bottom one has
FlxG.height (in our case 480).
Compile the game again and you should see that the paddle is now in position at the bottom of the screen!
That’s it for part 1. We’ve learned something about the anatomy of a HaxeFlixel project, met some basic classes and even put a paddle on screen. Not bad! Next up, we’ll add a ball and some walls. Be excellent to each other, and party on!
If you have any questions, comments or criticism, post them in the comments below or reach out to me on Twitter @ohsat_games!
Download the project files!Become an excellent patron on Patreon and grab the complete source code for this tutorial, as well as other bodacious perks such as early access!
You will also be added to the Wall of Excellent People!
Check out the rest of this tutorial series!