Sites to use
The official Phaser website is here.
Additionally, because we are going to use Phaser 3, the latest release, the examples on the site will most probably not work for v3. If you want some examples of v3 features the link is here.
You should not need the examples during this tutorial but if you want to learn further that is where you start. Google works as well but be careful about which version is being discussed. Version 3 is relatively new and v2 has loads more documentation and examples and tutorials on it. However, I would recommend learning v3 because it is generally better in many ways and the knowledge will last you longer and it will be more current.
Prerequisites (what you need before doing this tutorial)
The pre-requisites are:
- Some time and patience.
- 3 rolls of duct tape.
- Lots of cardboard
Let's Get Started!
The repl.it project that I will be using for this tutorial is here and the website for it if you just wanna play the game is here. If you ever get stumped on a step that I take in this tutorial just check the repl and see how the code looks in it. If all else fails a bit of copy-paste will solve your issues.
Make a new HTML/CSS/JS repl and follow along...
So, first of all we need to include the Phaser script into our website. The only piece of HTML in this tutorial will be the following:
<script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.min.js"></script>Just paste this into your project's HTML file right above your script tag that links to
script.js. The order is important and if you get it wrong nothing will work. If your project is not working you should definitely have a look at the order of your scripts. The Phaser script should be first.
With that out of the way, let's get into making our game!
The first bit of code is a standard template that is in most simple Phaser games (more advanced ones may use a slightly different structure but the idea is the same).
The code looks like this:
While this may look alien to you, don't stress. To follow along this tutorial you don't need to understand what everything does exactly. The main things you should pay attention to are:
- The three functions at the bottom
update. These we will fill in with the game's code.
heightproperties. You can set these to anything you like, I did not make it
window.innerHeightbecause scaling can quickly become messy. It is easier to make it a fixed width for everybody.
So now if you run your repl you should see a black square in your browser window. Success! If you do not, make sure you have the Phaser script in the right place and that you have the code in your
script.js exactly like above. You should also get a message in the console, something like:
%c %c %c %c %c Phaser v3.14.0 (WebGL | Web Audio) %c https://phaser.io background: #ff0000 background: #ffff00 background: #00ff00 background: #00ffff color: #ffffff; background: #000000 background: #fff
This may look awful in the repl.it console but if you open it in a new tab and check the console it should be a colorful banner.
preload function that we are going to use for this section is where you load your assets. If you want some images or audio (Phaser does that as well) in your game you first have to load it here. This way you are loading all the required assets immediately and you can use them throughout the game.
I have made some assets for this tutorial so that you do not need to find or make some yourself. Go here and click download like so to get the files:
If you get the files in a
.zip folder just unzip them and drop them into your repl. Once you have them in your repl we have to load them into our game. The following code in the
preload function will do the trick:
The first parameter in all of the functions is the "key" for the image. This key you would use when you need to add the image into the game. You can put it as whatever you want but make sure it is descriptive of the image in some way. I suggest you keep them the same as mine so that later code in my tutorial works for you. The second parameter is the path to the image. Because I put the assets in the same folder as the html and js files the path is just the name of the image. If you put your assets in another folder the file path string would look like
"folder_name/file_name.png". You may also have noticed that the first command is a bit different. It loads an atlas and not an image. An atlas is a collection of images put together to make a larger image accompanied by a file that states where all the smaller images are. If you open the file
sprites.json in the assets I gave you you should see that it contains a bunch of named objects that have x, y, width and height properties among others. Each object is an image inside the larger image. In this tutorial we will use the atlas for the player animations. All of the frames for the player (in our case only three) are in the
spritesheet.png file. The third parameter for the atlas is the path to the
.json file which we looked at already.
If you now run the current code the screen should remain black and no errors should be in the console. If you see a web audio warning that is fine, it does not mean anything important. It's just chrome messing with you.
Adding Objects to Our Game
create function is where the building of our game happens. It is run right after
preload and is run only once. If you want to add an object to the game, this is where you do it. If you want to repeatedly create some object. Make a function (read below) that creates the object and run that as may times as you like.
So we now have loaded some images but we need to have something happen on the screen. Let's add a function in the
create function that will spawn our player in. Add this code to the
I put this in a seperate function so that we can spawn the player multiple times. We are saving the player to
this which is the Phaser game object so that we can access it from anywhere. The function itself creates a sprite (image/object) that is in the Phaser physics system. The parameters are:
1. X position
2. Y position
3. Image key
4. (optional) If the image is an atlas, which frame in the atlas.
There may be a few more parameters but those are not important for this tutorial.
The way we find out which frame is which in the atlas is by looking at the
sprites.json file. Find an object and look at its x and y properties. For example
sprite_2 has the following object:
We can see that the x and y coordinates of the frame are
0, 0. This means that it will be in the top left corner. If you look at the top left corner of the
spritesheet.png image you will see which frame is
sprite_2. Try changing the last parameter in the add function to be
sprite_2. You will see that it has changed.
Adding a Background
If the only background color we could have would be black Phaser would look really bad. Luckily enough, Phaser has an easy way to add a background to our game. Just add this code to the top of your
create function above the
This sets the background color for our main camera to white. If you have not used hex color codes before don't worry about it, just know that
#ffffff is white. The only problem with that is that now we can't see where our canvas window starts and ends. We can fix this with a little CSS:
Now if you run your code it should look something like this:
You can see we have our little character in the middle of the screen. The background is now white. You may have noticed that the character is not offset to a side even though we put in the coordinates for the center of the screen. This is because Phaser draws images from their center. This makes it easier to center images.
Another simple thing we can add to the game is a camera that follows the player. This is quite easy to do in Phaser:
The function should be quite self-explanatory and if you run it you should see no change for now. As long as you do not get any errors you are fine.
Before we start I wanted to show you the most basic way to add an image to the game. The method used above has a very specific use case (only for sprites). Here is a more general use way of doing it:
This is good for some simple use cases like for example a logo image in your title screen. However it has its shortcomings. Imagine you want to create a map of these platforms. You would have to add
platform2 and so on... It would be a nightmare. Let's not get started on collisions. So by now you can see why we are not going to use this to add our platforms. Instead we will have a group. Defining a new group is easy. Remove the above code and add this instead.
Currently we are just defining a new static (non-moving) group and assigning it to the variable
this.platforms. If you run this now the platform image will disappear. That is because we need to add some platforms to the group. This can be done simply like this:
There we go! Now we have our platform back! But what is the benefit? In a moment when we deal with collisions you will see why. For now we will leave the platforms and get back to them later.
As you have probably gathered by now, Phaser has made its own version of everything you may need when developing games. Keyboard inputs are no exception. Phaser even supports many ways to do keyboard inputs. We are going to do the shortest and simplest. We are going to have a bunch of variables, one for each key. And we will check each frame if any of the keys are pressed and set velocities accordingly. The code for the keyboard variables in the
create function looks like this:
You do not need to understand this, just get the idea of what is happening. When a player presses a key the variable associated with that key will have
isDown set to
true. This makes adding keybinds really easy.
Now for the rest of this section we are using the
update is your game loop. This function is run very fast repeatedly all throughout your game. This is where you would handle things like movement and other stuff you would want to check every frame. If you would be coding your own physics this would be where you do it.
update function now let's check if the W key is pressed:
Instead of incrementing or decrementing the Y property of the player we set its velocity. We do this because it sets a velocity within Phaser which has some benefits. First of all Phaser object velocities take into account the frame rate. If every frame you increase the position X of a player, the higher the frame rate the faster the player moves. However, Phaser counteracts this. We do not need to know how, just that no matter the frame rate the player will always move at the same speed. The value we put into
setVelocityY is the amount of pixels we want it to move in one second.
If you run this now you will see that is you press the W key your character will move up. Success! Now let's add keybinds for A and D. This is only a few more lines of code:
We have this in an if/else if statement because we don't want to head left and right at the same time. We can only go in one direction or the other. And that's it! We now have linked up our keyboard keys to our Phaser game! Now it's time to deal with physics.
Phaser also has its own physics engine. In fact it has three but we will only use the most basic one for this tutorial. Just simple square and square collisions. Before we can do collisions, how about we add some gravity. We only need it on the player so it would look like this:
Now if you run your game you will see that the player drops. But he is dropping very slowly. Why so? This is because each frame we are setting his velocity to 0 if the W key is not pressed. Previously that was needed so that he would not just fly away but now we need to remove that bit:
Now if you run it the player falls a bit faster. You can still fly with W but we will change that in a second.
Now that we have gotten gravity mostly out of the way let's make the player collide with the platform that we have.
We can do this with one simple line of code. Add this to your
That's it. Just one line of code does everything. But if you run this now it will not work. The player will fall right through. And this is actually for a really stupid reason. We are running this code before we add the platforms. All you have to do is move the
spawnPlayer function call (not the function itself) below where we add the platforms. And Viola! We have the player not falling through the platform. There are some small problems that we should address before moving on. First of all, When we press W we can fly endlessly. That defeats the point of the game. To prevent this all we need to do is to only let us jump when we are on the ground. This is easy to do:
When the key W is down and the player's body is touching a platform with its bottom it will jump. If you run this now you will see that the player now makes many little jumps if you press W. To make the jumps larger we have to increase the
And also while we are at it we can make the left/right movement a bit faster:
So there we have it! A running and jumping player! Now let's give him a map to run around in.
Phaser supports multiple ways to build a map (of course). However, I have decided that it would be better to cook up our own map builder that would work off of a string. Spaces would indicate that at that position there is no platform, 1 would mean that there is, 2 that this is a spawn point for the player and a dot(.) would mean that this is the end of a row. The map I designed looks something like this:
You can see that it is a box that is riddled with platforms. How do we turn this into a map? The parser for this that I made is only a few lines of code:
First we split the string that we have into an array of rows using the . that says that a row ends at that point. Then we loop through each row and at each row we loop through each character in the row. If the character is a 1, we add a platform at that place. If the character is 2 we spawn the player. I have a bit more code there that checks if there is a platform to the left or right and that nudges the character to a side just so that the player does not spawn in a platform. Also, you may have noticed that we are calling
spawnPlayer here with some parameters. These are just x and y coordinates of where to spawn. To make that work we just have to edit the
spawnPlayer function like so:
Now if you run this you should get a map inside of which the player can run around. You can mess around with the map string if you want and design your own map. I would love to see what you come up with in the comments!
A while ago, I mentioned that we would use the atlas for player animations. Now is the time! We have three frames in our atlas and we have only used one. It's time to use the other two. Phaser has its own animation manager (by now you get the idea - Phaser === everything) that makes it super simple to do animations. First we have to set up our animations:
This creates an animation for our player that we can play when we want. The array
frames is what Phaser will loop though and play.
frameRate is quite self explanatory - the amount of frames that are played each second.
repeat with the value -1 will make the animation loop again and again. Not specifying
repeat will just make it run once. The key is the string that we can use to reference to the animation later. Just the same way as with images. Now let's run the animations when we walk right or left:
true parameter is just whether if there is already an animation running, should Phaser continue it? If you set this to false you will see that it will just freeze on a frame. That is because every frame it is checking if a key is pressed and then playing the animation. It will start again every frame making it look like it is frozen. Now if you run this you will see that we have a running animation with the legs moving and the hat bobbing up and down. There is only one more problem with the sprite. The player does not flip when he runs to the left. This is an easy fix:
There we go! Now we have a map, player animations, keybinds, physics and most of all - a weird blob of a character who has a hat that flaps in the breeze!
The Final Step - Spikes and Coins
Now let's add some spikes that the player has to dodge and some coins that the player can collect. First, let's add a score counter in the top of the screen that displays our score:
setScrollFactor(0) will make sure that when our camera moves, the text does not. This way it will always be in the same position in the top-left of the screen. Text is drawn from its top-left (don't ask me why it is one way for one thing and another for another) so drawing it at
0, 0 will put in the top-left corner.
setDepth(200) will make sure the text always appears on top. We also make a variable for the score of the player that can be increased when we collect a coin.
Time to make an incentive to run and jump around. Coins will be a
c in our map string. So, the map would now look like this:
Now to make this work we have to add an option of what to do if the current character is a
c in our map parser. I added something like this:
If you run this you will see that a bunch of little coins appear. But we can't collect them! This is fairly easy to add:
This function will check if there is an overlap between two objects. The two objects are the first two parameters. If there is an overlap, it will run the function that is passed in with the third parameter.
null is just there for reasons and
this is just passing on the
this value to the function. We now need to make a function
collectCoin that will run if there is an overlap:
If you run this you will see that you can now collect coins and increase your score. Success! There is only one more step before we are done.
Time to add some difficulty to the game. We are going to have spikes that if you step on they will clear your score and respawn you. Let's first add them to our map as an
And now we can render them into our game:
Let's do what we did last time - add an overlap detector between the player and the spikes. The code is pretty much the same:
And now we have to make a function
die that will be run when the player hits the spike. All we will do is stop the game and display text saying YOU DIED:
this.physics.pause is what stops the game. The text adding should be pretty self explanatory. The bit that may be confusing is the line after that. This is the code I used to center the text. It accepts two arguments - the object to center and the zone in which to center it in.
this.add.zone in turn accepts four arguments - the x, y, width and height of the zone. The x and y are in the center of the screen and the width is the width of the screen and the same for the height. When you run this code and jump on a spike you will see that it shows some big red text saying YOU DIED.
And there we have it! Our completed game! Make sure to celebrate by wrapping lots of duct tape around some cardboard. That was what the duct tape and cardboard were for. Nothing, really :).
Thank you for sticking to the end of this monster of a tutorial. I hope you are proud of what you have made. If you liked this tutorial, please show support by voting for it. If you have any questions, suggestions or if you found a typo don't hesitate to post it in the comments! Also, if you put a spin on the game or make a cool map that be sure to share it! I would love to see what you guys can make out of this :). If you are too lazy to scroll up, the link to the repl that I made is here. Also, if you would like me to make some follow up tutorials outside of the competition about some more advanced features like scenes and (multiplayer?) then be sure to leave a comment. If enough people want it I will be sure to make some more tutorials.
I made an additional demo that delves into some more complicated concepts but it looks a lot better (I stole some sprites off the internet). It is just some uncommented code that you can play around with and try and see if you can make anything out of it. If you want to check it out you can find it here. Just wanna play it? Go here. Also, thank you guys for all the support in the comments! So heartwarming to see that many people like it.