noobtuts

Unity 2D Flappy Bird Tutorial

Unity 2D Flappy Bird Game

Foreword

Flappy Bird was a mobile game released in 2013 and became one of the Apple App Store's most downloaded application in January 2015. The game play is very simple: a bird is supposed to fly horizontally between obstacles while avoid them. The player taps a button to make the bird flap its wings, causing it to fly upwards. The game is over if the bird hits any obstacles. Simple, right?

Today's tutorial will show you how to make a Flappy Bird clone in just over 40 lines of code, a few sprites and you'll also learn some new knowledge along the way.

As usual, everything will be explained as easy as possible so everyone can understand it.

Requirements

Knowledge

Our Tutorial does not require any special skills. If you know your way around Unity and heard about GameObjects and Transforms before, then you are ready to go. And if you didn't, don't worry about it too much.

Feel free to read our easier Unity Tutorials like Unity 2D Pong Game to get used to the engine before tackling this tutorial.

Unity Version

Our Flappy Bird Tutorial will use Unity 2018.4 LTS installed through the Unity Hub. Please adapt this guide to your version of Unity, however to keep things simple, we recommend using the same version as the guide. That doesn't mean you can't use a newer Unity version as they should work fine as well, but keep in mind that older versions may or may not work.

Project Setup

Let's get to it. We will start Unity Hub and select New:
Unity Hub, Clicking New Button

We will name it FlappyBird, select any location like C:\GameDev, select 2D and click Create Project:
Unity Create new 2D Project

Note: Avoid saving projects in any location like your Documents or Desktop. This may cause "path name too long" errors from Unity. The shorter the path, the better.

After Unity has created the project and loaded the Editor, it's time to start making our Flappy Bird game. Firstly, select the Main Camera in the Hierarchy and then set the Background Color to a light blue (R=198, G=208, B=230) for the sky color and adjust the Size like shown in the following image:
Camera Properties
Note: You might need to modify the value for the Size setting as this will adjust the scaling of the play field. Depending on your screen resolution, parts of the scene might be visible that would normally be off-screen on a lower screen resolution. This is normal and merely just a cosmetic issue.

The Background

We will begin by drawing a very simple sky background in our drawing tool of choice:
Flappy Bird Background
Note: right click on the image, select Save As..., navigate to the project's Assets folder and save it in a new Sprites folder.

After saving it, we can select the background in the Project Area:
Background in Project Area

And then modify the Import Settings in the Inspector:
Background Import Settings
Note: a Pixels Per Unit value of 16 means that 16 x 16 pixels will fit into one unit in the game world. We will use this value for all our textures, because the Bird will be 16 x 16 pixels, which should end up being 1 unit in the game world.

Alright so let's add the background to the game world by dragging it from the Project Area into Hierarchy:
Background to Hierarchy

Now, in the Hierarchy view, drag the "background" item into the Main Camera, so that the background becomes a child of the Main Camera:
Background as Child of Camera 1

Your hierarchy should up like this:
Background as Child of Camera 2

Now that the background is a child of the camera, it will always go where the camera goes. Or in other words, the player will always see the background.
Note: we could also place several backgrounds next to each other so that there is still a background when the camera moves horizontally, but making it a child of the camera is much easier.

Let's take a look at the Inspector and position the background one unit lower at Y=-1, just so that it fits to the rest of the game later on:
Background position

If we press Play then we can already see the background sky:
Background in Scene

There is one more adjustment to be made here. We will add the bird and some obstacles soon, so let's also make sure that the background is really drawn behind everything else. Unity uses the SpriteRenderer's Sorting Layer and Order in Layer properties to decide which parts of a game should be in front of which other parts.

We will simply set the Order in Layer to -1 so that everything else will be drawn in front of it:
Background Order in Layer
Note: the higher the order, the more it is in the foreground. The lower the order, the more it is in the background.

The Ground

Let's also draw some kind of terrain for the ground. We will make it very wide so that there is enough space for our obstacles later:
Flappy Bird Ground
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We will select the ground in the Project Area and then assign the same Import Settings that we used before:
Ground Import Settings

Afterwards we will drag it from the Project Area into the Hierarchy again:
Add Ground to Hierarchy
Note: This time we won't make it a child of the camera.

Let's take a look at the Inspector. We'll position the ground at X=16 Y=-6, and set Order in Layer to 1. This positions the ground lower in the playfield, and also makes sure the ground is rendered in front of everything else.
Ground position

Ground Physics

The ground should the part of the physics world. Right now it is really just an image in the game world, just a visual effect and nothing more. We want the ground to be like a wall that the bird can collide with, so let's select Add Component -> Physics 2D -> Box Collider 2D in the Inspector:
Ground Collider

Normally we would be done now, but there is one more adjustment to be made here. Later on we will add obstacles to our game (like the green pipes in the original Flappy Bird game), and those obstacles will move upwards and downwards into the ground. The obstacles and the ground will both be part of the physics world, and according to the laws of physics, there can never be two objects at the same place (or in our case, two Colliders).

There are several ways to work around this. As usual we will choose the easiest way by creating a new physics Layer that we will use for the ground and the obstacles. Afterwards we will tell Unity to simply ignore collisions in-between that layer.

We can create a new layer by selecting Add Layer in the Inspector after clicking the Layer dropdown, which will be set to Default... by default.
Layer

Afterwards we will add one User Layer, let's call it WeirdPhysics:
Weird Physics Layer

Now we can select the ground in the Hierarchy again and then assign the WeirdPhysics layer:
Ground WeirdPhysics Layer

Afterwards we select Edit -> Project Settings. This will bring up a new pop-up window. In the sidebar of the new pop-up window, we must select Physics 2D and disable the WeirdPhysics vs. WeirdPhysics collisions in the Layer Collision Matrix:
Physics ignore WeirdPhysics Layer Collisions
Note: it's very rare that we have to do this in Unity, but our Flappy Bird game is one of those exceptions.

Now the ground will never collide with any of the obstacles.

Also if we press Play then we can see the sky and the ground already:
Ground in Scene

The Bird

The Bird Image

Alright, let's get to the most important part of our game: the bird. We will begin by drawing a bird flying animation with 4 frames:
Bird Animation
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We will use the following Import Settings as pictured below. Since our bird image contains several smaller images, hence it's important that we select Multiple as Sprite Mode. Afterwards, click Apply. Then we click the Sprite Editor button:
Bird Sprite Importing

In the Sprite Editor we Slice it as a 16 x 16 Grid:
Bird SpriteEditor Settings

After pressing the Slice button we can close the Sprite Editor. Unity will ask us if we want to apply the Unimported Import Settings, so let's select Apply.

Now we can see our 4 slices as children of the bird image in the Project Area:
Bird Children

The Bird Animation

Let's select all the slices and then drag them into the Hierarchy:
Drag Bird Slices to Hierarchy

Unity knows that we want to create an animation from those slices, which is why it asks us where to save the animation files. We will create a new BirdAnimation folder and then save the animation as fly.anim.

Afterwards we can see two new files in our BirdAnimation folder:
Bird Animation Files

The bird_0 file is the state machine that takes care of animation states and speeds. The second file is the fly animation itself. Let's double click the bird_0 file really quick so that we can see the animation state machine:
Bird in Animator

Note: we don't have to worry about the animation states because we only have one animation.

We will click on the fly state and then simply decrease the speed to 0.5 in the Inspector:
Bird Fly Animation Speed

And since we only have one animation, we are already done here. If we press Play then we can even see it in action:
Bird animated

Bird Physics

Our bird is supposed to be part of the physics world. Let's begin by giving it a Collider, just like we did with the ground. Select the bird object in the Hierarchy, and in the Inspector, click Add Component -> Physics 2D -> Circle Collider 2D:
Bird Collider

Now everything in the physics world that is supposed to move around will also need a Rigidbody. A Rigidbody takes care of things like gravity, velocity and movement forces. Luckily, we can add a Rigidbody by selecting Add Component -> Physics 2D -> Rigidbody 2D in the Inspector.

We will also make sure we freeze the Z Axis from rotating so that the bird doesn't suddenly rotating in the air and cause some really weird visuals.
Bird Rigidbody

Note: You could untick this option for amusements, but that's up to you.

If we press Play then we can already see the Rigidbody's gravity property in action:
Bird Gravity

The Bird Movement Script

Our bird already looks pretty decent, but it should also fly towards the right at all times, and it should flap its wings to fly upwards if the user presses a button.

This kind of behavior can be implemented with a Script. Without Scripts, the game will be lifeless and nothing will move. Making sure the Bird object is selected in the Hierarchy, select Add Component -> New Script in the Inspector, name it Bird click Create. We will also create a new Scripts folder in our Project Area so that we can put the Bird Script into it:
Bird Script in Project Area

We can double click the Script in order to open it:

using UnityEngine;
using System.Collections;

public class Bird : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

We can make the bird fly towards the right at all times by first adding a new speed variable and then using the Rigidbody's velocity property:

using UnityEngine;
using System.Collections;

public class Bird : MonoBehaviour {
    // Movement speed
    public float speed = 2;

    // Use this for initialization
    void Start () {    
        // Fly towards the right
        GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

Note: The velocity is exactly the movement direction multiplied by the movement speed.

If we save the Script and press Play then we can see how the bird flies towards the right of the Screen.

Now we create a new force variable and then use our Update function to check for key presses. If the user pressed the Space key then we will make the bird fly upwards with the force:

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class Bird : MonoBehaviour {
    // Movement speed
    public float speed = 2;
   
    // Flap force
    public float force = 300;

    // Use this for initialization
    void Start () {    
        // Fly towards the right
        GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
    }
   
    // Update is called once per frame
    void Update () {
        // Flap
        if (Input.GetKeyDown(KeyCode.Space))
            GetComponent<Rigidbody2D>().AddForce(Vector2.up * force);
    }
}

If we press Play then we can now make the bird fly upwards:
Bird flapping

There is one last thing to do here. We want to restart the game as soon as the bird collided with the ground or with an obstacle. Our bird already has a Collider and a Rigidbody, which means that Unity automatically calls the OnCollisionEnter2D function. All we have to do is actually add it to our Script:

void OnCollisionEnter2D(Collision2D coll) {
      // Restart
      SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

Note: SceneManager.LoadScene, inside the UnityEngine.SceneManagement namespace can be used to load a Scene. SceneManager.GetActiveScene() represents the currently loaded Scene, and we simply tell the SceneManager to reload the current active scene. Or in other words, we simply restart the current Scene.

Note 2: In earlier versions of Unity, you would use Application.LoadLevel() to load a scene. However, this has been deprecated (scheduled to be removed) as of Unity 2018. To work around this, we use the SceneManager class which is the recommended way of loading scenes. Don't worry about the SceneManager and friends too much, as that's outside the scope of this tutorial.

Our finished script looks like the following:

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class Bird : MonoBehaviour {
    // Movement speed
    public float speed = 2;
   
    // Flap force
    public float force = 300;

    // Use this for initialization
    void Start () {    
        // Fly towards the right
        GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
    }
   
    // Update is called once per frame
    void Update () {
        // Flap
        if (Input.GetKeyDown(KeyCode.Space))
            GetComponent<Rigidbody2D>().AddForce(Vector2.up * force);
    }
       
    // Called when a collision occurs (ie. Bird hits the ground, or a object)
    void OnCollisionEnter2D(Collision2D coll) {
        // Restart
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
}

Very nice.

Camera Follow

Right now the Camera never moves. Since the bird always flies towards the right of the screen, we won't be able to see it past the right side of the screen. We will solve this problem by creating a new Script that makes the Camera follow the bird all the time.

Let's select the Main Camera in the Hierarchy and then click on Add Component -> New Script, name it CameraFollow and Create. We will also move it into our Scripts folder and then open it:

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

We won't need the Start function this time, so let's remove it:

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour {
   
    // Update is called once per frame
    void Update () {
   
    }
}

Let's add a public Transform variable to specify which target to follow:

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour {
    // The Target
    public Transform target;
   
    // Update is called once per frame
    void Update () {
   
    }
}

Note: we can set that target in the Inspector later on.

Afterwards we will simply use the Update function to always set the Camera's X position to the target's X position:

// Update is called once per frame
void Update () {
    transform.position = new Vector3(target.position.x,
                                     transform.position.y,
                                     transform.position.z);
}

Note: the X position is the horizontal position, while the Y position is our vertical position.

Now our Script is done. However it's usually considered best practice to do Camera Movement after everything else in the Scene was updated. We will simply change our Update function to LateUpdate, just to have it perfectly smooth:

void LateUpdate () {
    if(target == null) return;
    transform.position = new Vector3(target.position.x,
                                     transform.position.y,
                                     transform.position.z);
}

Note: We check to see if the target variable (which is a Transform) is null. If it evaluates to true, we tell Unity to stop processing the LateUpdate function. Otherwise, we continue execution of the LateUpdate function. By doing this, known as null checking, you can avoid a flood of errors in the Unity Console complaining that something wasn't set correctly.

If we save the Script then we can take a look at the Inspector and drag the bird_0 GameObject from the Hierarchy into the Script's Target slot:
Camera Follow Target

If we press Play then we can now see how the Camera automatically follows the bird. If the camera doesn't, then make sure you've set the Camera Target as seen above:
Camera following the Bird

The Obstacles

The Obstacle Image

Right now our game is not very hard. We can change that by adding some obstacles. Let's draw one:
Obstacle
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We will use the following Import Settings for it:
Obstacle ImportSettings

And then drag it from the Project Area into the Hierarchy in order to create a GameObject from it:
Obstacle in Hierarchy

We will position it at X=3, Y=-5:
Obstacle Position

Here is how it looks in the Scene:
Obstacle in Scene

Obstacle Physics

The obstacle should be part of the physics world again. The bird should be able to collide with it, so let's select Add Component -> Physics 2D -> Box Collider 2D in the Inspector:
Obstacle Collider

We talked about how the obstacles might end up inside the ground and how we don't want the two to collide with each other, so let's make it part of our WeirdPhysics layer, too:
Obstacle Layer
Note: since we disabled collisions in-between our WeirdPhysics layer, the ground will never collide with an obstacle. The bird can still collide with the ground and with the obstacle because it has a different layer (the default one).

We're getting there. Now, some of the obstacles are also supposed to move up and down. Everything in the physics world that is supposed to move will need a Rigidbody, so let's select Add Component -> Physics 2D -> Rigidbody 2D in the Inspector again. We don't want it to be affected by gravity, so let's set the Gravity Scale to 0. We also don't want it to rotate, so let's also make sure we freeze the Z axis.
Obstacle Rigidbody

If we press Play and let the bird fly against the obstacle then we can see how the level restarts:
Bird vs Obstacle

Obstacle Movement

Right now, our obstacles are static, meaning they won't move at all. In Flappy Bird, some of the obstacles are supposed to move up and down. To accomplish this kind of behavior, we'll harness the power of Scripting again. Let's select Add Component -> New Script, name it Obstacle, move it into our Scripts folder. Once it's inside our Scripts folder, let's open it:

using UnityEngine;
using System.Collections;

public class Obstacle : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

There are many different ways to make the obstacle move up and down all the time. As usual, we will use the easiest way as it'll "just work".

We will begin by adding a speed variable and then setting the Rigidbody's velocity so that the obstacles move upwards with the speed:

using UnityEngine;
using System.Collections;

public class Obstacle : MonoBehaviour {
    // Movement Speed (0 means don't move)
    public float speed = 0;

    // Use this for initialization
    void Start () {
        // Initial Movement Direction
        GetComponent<Rigidbody2D>().velocity = Vector2.up * speed;    
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

Now the trick is to use Unity's InvokeRepeating function to reverse that velocity every few seconds:

using UnityEngine;
using System.Collections;

public class Obstacle : MonoBehaviour {
    // Movement Speed (0 means don't move)
    public float speed = 0;
   
    // Switch Movement Direction every x seconds
    public float switchTime = 2;

    void Start() {
        // Initial Movement Direction
        GetComponent<Rigidbody2D>().velocity = Vector2.up * speed;
       
        // Switch every few seconds
        InvokeRepeating("Switch", 0, switchTime);
    }
   
    void Switch() {
        GetComponent<Rigidbody2D>().velocity *= -1;
    }
}

Note: the Switch function simply reverses the Rigidbody's velocity. We then use InvokeRepeating to tell Unity to call that function every few seconds. We also added a switchTime variable to specify the time in which Switch should be called.

Let's save the Script and set the obstacle's Speed to 1:
Obstacle Script in Inspector
Note: if we don't want an obstacle to move then we can either set it's Speed to 0 or disable the Script.

If we press Play then we can see our obstacle moving up- and downwards:
Obstacle moving

Adding more Obstacles

Let's right click the obstacle in the Hierarchy, select Duplicate and move it a bit further towards the right:
Duplicated Obstacle

We will also duplicate one and then set the Scale.Y property to -1:
Obstacle Scale Y-1

This way it looks properly when positioning it upside-down:
Obstacle upside-down

We can add as many obstacles with as many different speed and switchTime properties as we want:
Unity 2D Flappy Bird Game

Summary

Congratulations! You've just completed how to make a Flappy Bird-like game in Unity.

We just learned how incredibly easy it is to make the said game in Unity. We used some very powerful Unity features like Physics, Mecanim (for the player birds' animation), Layers, the Sprite Editor and Scripting. As usual, it's now it's up to the reader to make the game fun and more difficult.

The completed project files can be downloaded here.