noobtuts

Unity 2D Angry Birds Tutorial

Unity 2D Angry Birds

Foreword

Angry Birds was released in December 2009 and thanks to its highly addictive gameplay it soon became the most successful mobile game of all time.

In this Tutorial we will implement a Angry Birds clone in Unity. The most complex part of the game is the physics system, but thanks to Unity we won't have to worry about that too much. Using Unity will make it so easy that we will only need about 100 lines of code!

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

Here is a preview of the final game:
Unity Angry Birds

Requirements

Knowledge

Our Tutorial does not require any special skills. If you know your way around Unity and heard about GameObjects, Prefabs and Transforms before, then you are ready to go.

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

Unity Version

In this Tutorial we will use Unity 5.0.0f4. Newer versions should work fine as well, older versions may or may not work. The free version of Unity 5 now comes with all the engine features, which makes it the recommended version.

Project Setup

Let's get to it. We will start Unity and select New Project:
Unity New Project

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

Afterwards we can select the Main Camera in the Hierarchy and then set the Background Color to a friendly blue tone (red=187, green=238, blue=255) and adjust the Size and the Position like shown in the following image:
Camera Properties

The Ground

The Ground Sprite

In order to prevent Copyright issues we can't use the original Angry Birds graphics in this Tutorial. Instead we will draw our own Sprites and make them look similar to the original game.

Let's start by drawing the ground with our drawing tool of choice:
Ground
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

After saving it into our Project, we can select it in the Project Area:
Ground in Project Area

And then modify the Import Settings in the Inspector:
Ground Import Settings
Note: a Pixels to 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. We chose 16 because the bird will have a size of 16 x 16 pixels later on and we want it to have the size of 1 unit in the game world.

Alright, now we can drag the ground image from the Project Area into the Scene:
Drag Ground into Scene

Let's take a look at the Inspector and position the ground at (0, -2) so that everything above y=0 is not part of the ground:
Ground Position

Ground Physics

Right now the ground is only an image, nothing more. It's not part of the physics world, things won't collide with it and can't stand on top of it. We will need to add a Collider to make it part of the physics world, which means that things will be able to stand on top of it instead of falling right through it.

We can add a Collider to it by selecting Add Component->Physics 2D->Box Collider 2D in the Inspector:
Ground Collider

The invisible Borders

We will add three borders around the level to make sure that things won't just fall out of it. Let's select GameObject->Create Empty from the top menu and then rename it to borders in the Inspector:
Borders renamed

We will set its position to (0, 0):
Borders positioned

Now we will add some kind of invisible area to the left, right and top of our level. And whenever something enters that area then it should simply be destroyed. This kind of behavior can be implemented with a Trigger, which is pretty much just a Collider that receives collision info but does not collide with anything.

We can add a Trigger by selecting Add Component->Physics 2D->Box Collider 2D in the Inspector and then enabling the Is Trigger option. We will also adjust its size and center so it will be positioned at the left of our level:
Borders with first Collider

Afterwards we can add two more triggers for the right and top sides of our level:
Borders with all Colliders

If we take a look in the Scene then we can see how the Triggers are nicely aligned around our level:
Borders in Scene

Now we still have to make sure that whatever enters the borders will be destroyed immediately. This kind of behavior can be implemented with a Script. We can add a Script to the borders by selecting Add Component->New Script in the Inspector. We will name it Borders and select CSharp as the language:
Create Borders Script

Unity then creates a new Script, stores it in our Project Area and adds it to the borders GameObject. We can even see it in the Inspector now:
Borders Script in Inspector

Let's also move the Script into a new Scripts folder, just to keep things clean:
Borders Script in Project Area

Let's double click the Script to open it:

using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

We won't need the Start or the Update function, so let's remove them. Instead we will use the OnTriggerEnter2D function that will automatically be called by Unity whenever something enters one of the border triggers:

using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    void OnTriggerEnter2D(Collider2D co) {

    }
}

And in this function we will simply Destroy whatever enters the Trigger:

using UnityEngine;
using System.Collections;

public class Borders : MonoBehaviour {

    void OnTriggerEnter2D(Collider2D co) {
        Destroy(co.gameObject);
    }
}

After saving the Script, our borders are finished. We will see later on that if we try to fire a bird outside of the level, it will simply disappear.

The Clouds

We will take a few extra minutes to add clouds to the background in order to make the level look better. As usual we will begin by drawing one:

Cloud


Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

Let's select it in the Project Area and then modify the cloud's Import Settings in the Inspector:
Cloud Import Settings

Now all that's left for us to do is to drag it from the Project Area into the Scene a few times and position each cloud where we want it to be:
Clouds ingame
Note: by just using a few repeating patterns and some very colors we can make the level look pretty good without much effort.

The Slingshot

The Slingshot Image

A Slingshot will spawn new birds and allow the user to fire them into the level. As usual we will begin by drawing the sprite:
Slingshot
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

Here are the Import Settings:
Slingshot Import Settings

Later on we will create a Script that spawns a new bird at the slingshot's position, or to be exact at the slingshot's Pivot. We will want to spawn the bird at the top of the slingshot instead of the center, this is why we set the Pivot to Top in the Import Settings.

The following image shows the difference between Center and Top:
Slingshot Pivots

Note: if we set the Pivot to Center then transform.position is the point at the center of the slingshot. If we set the Pivot to Top, then transform.position is the point at the top of the slingshot.

Alright, now with the Pivot set to Top we can drag the Slingshot into the Scene to the position (-22, 3):
Slingshot positioned

The Spawn Script

As mentioned before, our Slingshot is supposed to spawn the birds. To be exact, it should spawn one in the beginning, then wait for the user to fire it and then spawn another one as soon as all the physics calculations are finished (when nothing moves anymore).

We can implement such behavior with Scripting. Let's select the Slingshot in the Hierarchy and then click on Add Component->New Script in the Inspector. We will name it Spawn and select CSharp as the language. Afterwards we will also put it into our Scripts folder:
Spawn Script in Project Area

We can open the Script by double clicking it:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

The Start function is automatically called by Unity when starting the game. The Update function is automatically called over and over again, roughly 60 times per second. We won't need either of them so we can delete them from the Script.

There is yet another type of Update function, it's called FixedUpdate. It's also called over and over again, but in a fixed time interval. Unity's Physics are calculated in the exact same time interval, so it's always a good idea to use FixedUpdate when doing Physics stuff (which we will very soon).

Here is the modified Script with the FixedUpdate function:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {

    void FixedUpdate() {

    }
}

Alright let's add a variable that allows us to specify the Bird Prefab later on (the bird that we want to spawn):

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {
    // Bird Prefab that will be spawned
    public GameObject birdPrefab;

    void FixedUpdate() {

    }
}

And here is how we can spawn it:

void spawnNext() {
    // Spawn a Bird at current position with default rotation
    Instantiate(birdPrefab,transform.position,Quaternion.identity);
}

The Spawn Trigger Area

Now we can't just spawn one bird after another. Instead we will have to spawn one and then wait for it to be fired. There are several ways to implement this, but the easiest is to use a Trigger.

A Trigger is simply a Collider that receives collision information but is not actually part of the physics world. So if we add a Trigger to our Slingshot then we will get notified whenever something enters that trigger, stays in that trigger or leaves that trigger. However since it's just a Trigger, things won't collide with it like they would with a normal Collider (this will make more sense soon enough).

We can add a Trigger to our slingshot by selecting it in the Hierarchy and then clicking on Add Component->Physics 2D->Circle Collider 2D, giving it a fitting Radius and Center and then enabling Is Trigger:
Slingshot Collider in Inspector

We can also see the Trigger in the Scene:
Slingshot Collider in Scene

After adding the Trigger, we will get notified whenever something enters (OnTriggerEnter2D), stays(OnTriggerStay2D) or leaves(OnTriggerExit2D) that green circle shown above.

Now we can easily find out if a bird was already fired or if he is still in the trigger area by creating a occupied variable and then setting it to true when spawning a bird and to false when it leaves the Trigger:

using UnityEngine;
using System.Collections;

public class Spawn : MonoBehaviour {
    // Bird Prefab that will be spawned
    public GameObject birdPrefab;

    // Is there a Bird in the Trigger Area?
    bool occupied = false;

    void FixedUpdate() {

    }

    void spawnNext() {
        // Spawn a Bird at current position with default rotation
        Instantiate(birdPrefab, transform.position, Quaternion.identity);
        occupied = true;
    }

    void OnTriggerExit2D(Collider2D co) {
        // Bird left the Spawn
        occupied = false;
    }
}

Afterwards we can modify our FixedUpdate function so it always spawns a bird whenever the Trigger Area is not occupied anymore:

void FixedUpdate() {
    // Bird not in Trigger Area anymore?
    if (!occupied)
        spawnNext();
}

Note: !occupied means not occupied. We could also use if (occupied == false).

Our Spawn Script would work just fine now, but let's add one more feature. After shooting a bird, there will be plenty of things colliding with each other, falling down, rolling around or perhaps even exploding. In the original Angry Birds game a new bird is only spawned after all the things in the level stopped moving around.

We can very easily create a sceneMoving function that finds out if there is any object in the Scene that is still moving more than just a bit:

bool sceneMoving() {
    // Find all Rigidbodies, see if any is still moving a lot
    Rigidbody2D[] bodies = FindObjectsOfType(typeof(Rigidbody2D)) as Rigidbody2D[];
    foreach (Rigidbody2D rb in bodies)
        if (rb.velocity.sqrMagnitude > 5)
            return true;
    return false;
}

Note: we used the FindObjectsOfType function to get all the Rigidbodies in the Scene. Afterwards we check each Rigidbody's velocity, which equals the movement direction * speed. We then calculate the velocity vector's length by using sqrMagnitude and check if it's bigger than 5, in which case the object is still moving pretty fast and we return true. If none of the Rigidbodies are still moving then we return false.

With this neat little function in our toolbox we can easily modify our FixedUpdate function so a new bird is only spawned if nothing is moving anymore:

void FixedUpdate() {
    // Bird not in Trigger Area anymore? And nothing is moving?
    if (!occupied && !sceneMoving())
        spawnNext();
}

Now our Spawn Script is perfect, we can even see the Bird Prefab variable in the Inspector:
Spawn Script in Inspector
Note: we can't test the Spawn Script without the Bird yet, but it does work just fine as we will see after creating the bird.

The Bird

The Bird Image

Let's get to something more interesting: the Bird. We will begin by drawing a 16 x 16 pixel image of a bird with a big round body and some tiny wings and eyes:
Bird
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:
Bird Import Settings

Let's drag it from the Project Area into the Scene to create a GameObject from it:
Bird GameObject

Bird Physics

Right now the bird is just an image in the game world again. Let's make it part of the physics world by adding a Collider to it. We can add one by selecting the bird in the Hierarchy and then clicking on Add Component->Physics 2D->Circe Collider 2D in the Inspector:
Bird Collider

Now there is a Physics Material 2D slot in the Collider that allows us to give the bird some special physics properties. A Physics Material will be very useful in our Unity Angry Birds Tutorial because right now if the bird would fall on the ground it would look like this:
Bird hits the Ground without a Physics Material

Which looks a bit unnatural. Instead we want the bird to bounce off things a bit like this:
Bird hits the Ground with a Physics Material

All we have to do to create the bouncing effect in the second picture is to right click in the Project Area and select Create->Physics2D Material, name it BirdMaterial and move it into a new PhysicsMaterials folder:
Bird Physics Material in Project Area

Once selected we are able to modify the Material properties in the Inspector:
Bird Physics Material in Inspector
Note: the higher the Bounciness value, the more the bird will bounce.

Finally we can select the bird again and then drag the BirdMaterial from the Project Area into the Collider's Material slot:
Bird Collider with Material

The bird is also supposed to move around. A Rigidbody takes care of stuff like gravity, velocity and other forces that make things move. As a rule of thumb, everything in the physics world that is supposed to move around needs a Rigidbody.

We can add a Rigidbody to the bird by selecting Add Component->Physics 2D->Rigidbody 2D in the Inspector. It's important that we use exactly the same settings as shown in the following image:
Bird Rigidbody in Inspector
Note: we set the Gravity Scale to 4 because it makes the bird fall a bit faster.

If we press Play then we can now see the bird fall downwards and bounce off the ground:
Bird hits the Ground with a Physics Material

Our bird physics are finished, but there is one little adjustment that we have to make here. Right now if we would spawn the bird in the slingshot, it would fall to the ground immediately because of its Rigidbody's gravity. We only want the bird to be effected by gravity as soon as the user fired it, so let's enable Is Kinematic for now and disable it later from within a Script:
Bird RigidBody Kinematic

Now the Rigidbody is kinematic, which means that it's not effected by gravity or velocity, hence it won't fall down immediately.

Note: to make this more clear, anything like a hero, a car or a bird should have a Rigidbody with Is Kinematic disabled. We only enable Is Kinematic as long as the bird is still in the slingshot.

The Bird Prefab

As mentioned before, the bird should not be in the Scene from the beginning. Instead the slingshot should spawn a new bird when needed. In order for the slingshot to be able to spawn the bird, we will have to create a Prefab (or in other words, we have to save the Bird in our Project Area).

All we have to do to create a prefab is drag the bird from the Hierarchy into a new Prefabs folder in the Project Area:
Create Bird Prefab

Now we can load the bird into the Scene any time we want, which means that we can also delete it from the Hierarchy now:
Delete Bird from Hierarchy

Spawning the Bird

Let's select our slingshot in the Hierarchy and then drag the bird Prefab from the Project Area into the birdPrefab slot of our Spawn Script:
Spawn Script with Bird in Inspector

If we press Play then we can now see how the slingshot spawns a bird:
Slingshot spawns Bird

The Pull & Release Script

The user should be able to pull the bird around in the slingshot and then release it in order to shoot it into the wished direction.

We will create a new C# Script and name it PullAndRelease:

using UnityEngine;
using System.Collections;

public class PullAndRelease : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

The user will be able to drag the bird around a circle. Every circle needs a center and in our case it's the bird's spawn position, so let's make sure to save it in a variable:

using UnityEngine;
using System.Collections;

public class PullAndRelease : MonoBehaviour {
    // The default Position
    Vector2 startPos;

    // Use this for initialization
    void Start () {
        startPos = transform.position;
    }
}

Note: we also removed the Update function because we won't need it.

Alright, now in order to let the user drag the bird around in a circle we will have to find out if the bird was clicked (to be exact: dragged). We will also need to know if the user released the mouse, in which case we have to fire the bird towards the wished direction.

Of course, it wouldn't be Unity if there wasn't already a function for this. Unity automatically calls the OnMouseUp and OnMouseDrag functions whenever we drag a GameObject with the mouse or release the mouse afterwards:

using UnityEngine;
using System.Collections;

public class PullAndRelease : MonoBehaviour {
    // The default Position
    Vector2 startPos;

    // Use this for initialization
    void Start () {
        startPos = transform.position;
    }

    void OnMouseUp() {
        // ToDo: fire the Bird
    }

    void OnMouseDrag() {
        // ToDo: move the Bird
    }
}

Note: a MouseDrag happens if the user holds down the mouse button over a GameObject and then moves the mouse.

Moving the bird is really easy. All we have to do is convert the current mouse position to a point in the game world and then move the bird there. Of course, only as long as it is within a certain radius:

void OnMouseDrag() {
    // Convert mouse position to world position
    Vector2 p= Camera.main.ScreenToWorldPoint(Input.mousePosition);

    // Keep it in a certain radius
    float radius = 1.8f;
    Vector2 dir = p - startPos;
    if (dir.sqrMagnitude > radius)
        dir = dir.normalized * radius;

    // Set the Position
    transform.position = startPos + dir;
}

Note: we have to use ScreenToWorldPoint because the mouse is always somewhere between (0..width, 0..height), while the game position under the mouse can be just about anything, depending on the camera position. After finding the world position p, we simply calculate the vector from startPos to p. If this vector is too long (sqrMagnitude > radius) then we shorten it with dir.normalized * radius.

Alright, let's add our Script to the Bird by selecting it in the Project Area/Prefabs folder and then clicking on Add Component->Scripts->Push And Release.

If we press Play then we can now move the bird around a circle:
Bird Pull in Circle

Firing the bird into a direction is just as easy. We can use our OnMouseUp function to know when the mouse was released. Afterwards we will calculate the direction from the bird to the startPos and then use the rigidbody's AddForce function to fire it there:

// The Force added upon release
public float force = 1300;

void OnMouseUp() {
    // Disable isKinematic
    GetComponent<Rigidbody2D>().isKinematic = false;

    // Add the Force
    Vector2 dir = startPos - (Vector2)transform.position;
    GetComponent<Rigidbody2D>().AddForce(dir * force);

    // Remove the Script (not the gameObject)
    Destroy(this);
}

Note: as mentioned before, we will also disable isKinematic, so that the Rigidbody is effected by gravity and velocity again. We calculated the direction by simply subtracting the current position from startPos. Finally we remove the PushAndRelease Script from the bird so it can't be fired again afterwards.

If we press Play then we can now pull and fire the bird:
Bird Pull and Release

The Feather Particle Effect

Let's make the game a bit more smooth by adding a collision effect for the bird. As soon as it hits the ground for the first time it should spawn random feathers around itself like this:
Feathers

At first we will create a new Particle System by selecting GameObject->Particle System from the top menu. Afterwards we can select it in the Hierarchy and then rename it to feathers (right click and select rename, or press F2).

A Particle System is used whenever we need random particles to spawn, rotate and move into some direction. A simple example for a Particle System is smoke, where a gray texture is spawned and then moved upwards in a cone shape.

We will modify our Particle System so instead of making the particles fly upwards, it will make them fly into all directions. We will also modify some more specific things like the size, speed and rotation. There is no right or wrong Particle System for our feathers, so feel free to just play around with it until it looks like you want it to look. Here is what we came up with:
Feathers Particle System

And here is the image that we used for it:
Feather
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We will import it with the usual settings:
Feather Import Settings

Afterwards we can drag the image from the Project Area into our Particle System so it uses the image for all the particles.

Now we can drag the feathers GameObject from the Hierarchy into the Prefabs folder in our Project Area in order to create a prefab:
Feathers Prefab in Project Area

Afterwards we can then delete the feathers GameObject from the Hierarchy.

The last thing to do is to add a Script to our bird so that the feathers Particle System will be spawned in case of a collision. Let's select the bird Prefab in the Project Area and click on Add Component->New Script in the Inspector. We will name it CollisionSpawnOnce and select CSharp as the language. We will also move it into our Scripts folder again and then double click it to open it:

using UnityEngine;
using System.Collections;

public class CollisionSpawnOnce : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

We won't need the Start or Update function. Instead we will use the OnCollisionEnter2D function and a public GameObject variable for the prefab that should be spawned:

using UnityEngine;
using System.Collections;

public class CollisionSpawnOnce : MonoBehaviour {
    // Whatever should be spawned (Particles etc.)
    public GameObject effect;

    void OnCollisionEnter2D(Collision2D coll) {
        // Spawn Effect, then remove Script
        Instantiate(effect,transform.position,Quaternion.identity);
        Destroy(this);
    }
}

Note: to make sure that the effect is only spawned once, we will remove the Script from the bird with Destroy(this) (which only destroys the Script, not the whole bird).

After saving the Script, we can see the Effect variable in the Inspector. Now we can drag our feathers Particle System Prefab from the Project Area into the Effect slot:
Bird with CollisionSpawnOnce Script

If we press Play and fire the bird onto the ground then we can now see feathers spawning around it:
Feathers

The Trail

We will add yet another effect to our bird to make it look smoother: a trail of white dots that indicate the bird's trajectory:
Trail

At first we will need a few trail images with different sizes:

We will use the same Import Settings for each image:
Trail Import Settings

We want to be able to spawn the trail parts whenever we want, which means that we will need a Prefab for each of them. So let's select the trail_big image and drag it into the Scene and from there back into the Prefabs folder. We will repeat this for the trail_big and trail_small images until we have 3 Prefabs:
Trail Prefabs

Now we just need a Script that spawns one trail element after another, every second or so. Let's create a new C# Script and name it Trail:

using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

We can remove the Update function because we won't need it. Let's add a public GameObject[] variable that holds all the trail elements. We will use an Array, which just means that it's more than one GameObject:

using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;

    // Use this for initialization
    void Start () {

    }
}

We will also need a function that spawns the next trail. So for example it should spawn the first trail element, then next time it should spawn the second one, then the third one and then the first one again. This can be done by using Instantiate with a additional counter variable:

using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;
    int next = 0;

    // Use this for initialization
    void Start () {

    }

    void spawnTrail() {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}

What happens is that we set next to 0, which means that the first element in trails will be spawned as soon as spawnTrail is called. We then increase next by using next+1. To keep it in range of the trails array, we will also use % trails.Length, which uses the modulo (%) operation. For those who don't know modulo, here is a more obvious version:

void spawnTrail() {
    Instantiate(trails[next], transform.position, Quaternion.identity);
    next = next + 1;
    if (next == trails.Length) next = 0;
}

Now that we have a spawnTrail function we can use it to spawn a new trail element every 100 ms by using the InvokeRepeating function:

using UnityEngine;
using System.Collections;

public class Trail : MonoBehaviour {

    // Trail Prefabs
    public GameObject[] trails;
    int next = 0;

    // Use this for initialization
    void Start () {
        // Spawn a new Trail every 100 ms
        InvokeRepeating("spawnTrail", 0.1f, 0.1f);
    }

    void spawnTrail() {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}

Right now the trail elements would spawn all the time, even when the bird is not flying around. Let's add a little modification that only spawns a trail if the bird is flying fast enough:

void spawnTrail() {
    // Spawn Trail if moving fast enough
    if (GetComponent<Rigidbody2D>().velocity.sqrMagnitude > 25) {
        Instantiate(trails[next], transform.position, Quaternion.identity);
        next = (next+1) % trails.Length;
    }
}

Alright, let's save the Script and take a look at the Inspector again. Here we will drag in the three trail Prefabs from our Project Area:
Trail Script in Inspector

If we press Play then we can now see the trail after firing the bird:
Trail

The Wood Pieces

Let's add some structures like stones, ice and wood to our Unity 2D Angry Birds game.

We will begin by drawing a wood piece:
Pixel Art Wood Big
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

Here are the Import Settings for it:
Wood Big Import Settings

Now we can drag it into the Scene and position it somewhere on the ground:
Wood Big ingame

The wood piece is supposed to be part of the physics world, so as always we will begin by selecting it in the Hierarchy and then clicking on Add Component->Physics 2D->Box Collider 2D:
Wood Big with Collider

The wood piece should also be able to move around. Now it won't move on its own, but it should move if the bird flies into it. It should also be effected by gravity, so what we need is a Rigidbody. We can add one by selecting Add Component->Physics 2D->Rigidbody 2D. We will also increase the Mass to 4 so it's a bit heavier:
Wood Big with Rigidbody

Now we have a piece of wood that's part of the physics world!

We will repeat the same workflow for this slightly different wood piece:
Pixel Art Wood Long

Here is how our game looks after adding the second piece of wood and rotating the first one by 90°:
Both Wood Pieces ingame

The Stones

To have a few different types of structures in our game, we will also add two different types of stones:
Pixel Art Big Stone Pixel Art Small Stone
Note: right click each image, select Save As... and save them all in the project's Assets/Sprites folder.

The workflow will be the same like before, just that this time we will use an even bigger Mass for the Rigidbody:
Stone Physics

Here is how our game looks with some stones in it:
Stones ingame
Note: yet again we achieved some decent looking visuals with basic shapes, only a few colors and dithering.

The Ice

The Ice Image

We will add one more structure to our game: ice. This time it will be a bit more interesting though.

As usual we will begin by drawing a piece of ice:
Pixel Art Ice
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

The Import Settings are the same as always:
Ice Import Settings

Ice Physics

We will then drag it from the Project Area into the Scene just like we did with the stones and the wood. Now we can add physics to it:
Ice Physics

The ice should be really slippery, so let's right click in the Project Area and select Create->Physics2D Material and name it Ice Material:
Ice Material in Project Area

We will assign the following values in the Inspector:
Ice Material in Inspector

Afterwards we can select the ice in the Hierarchy and then drag the ice material from the Project Area into the Collider's Material slot:
Ice with Material

Destroying Ice on Impact

We also want the ice to be destroyed if it was hit by enough force, because that's what ice does naturally. We can implement this feature by selecting Add Component->New Script, naming it BreakOnImpact and using CSharp as the language. We will then move it into our Scripts folder again and then open it:

using UnityEngine;
using System.Collections;

public class BreakOnImpact : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

We won't need the Start or the Update function, so let's remove both of them. We will need a way to estimate a collision's force. We will keep it simple and multiply the speed with the mass:

float collisionForce(Collision2D coll) {
    // Estimate a collision's force (speed * mass)
    float speed = coll.relativeVelocity.sqrMagnitude;
    if (coll.collider.GetComponent<Rigidbody2D>())
        return speed * coll.collider.GetComponent<Rigidbody2D>().mass;
    return speed;
}

Note: Collision2D is the info that gets passed to the OnCollisionEnter2D function. It contains the relativeVelocity, which is pretty much the direction multiplied with the speed. If we only care about the speed then we can calculate the length of that vector by using sqrMagnitude. Now if the object that caused the collision also has a Rigidbody then we will multiply the speed with the Rigidbody's mass. Otherwise we return only the speed.

Alright, now we can use the OnCollisionEnter2D function to get notified about the collision. We will then compare the collision's force with a configurable variable. If it's bigger than that force then the ice will break:

using UnityEngine;
using System.Collections;

public class BreakOnImpact : MonoBehaviour {
    public float forceNeeded = 1000;

    float collisionForce(Collision2D coll) {
        // Estimate a collision's force (speed * mass)
        float speed = coll.relativeVelocity.sqrMagnitude;
        if (coll.collider.GetComponent<Rigidbody2D>())
            return speed * coll.collider.GetComponent<Rigidbody2D>().mass;
        return speed;
    }

    void OnCollisionEnter2D(Collision2D coll) {
        if (collisionForce(coll) >= forceNeeded)
            Destroy(gameObject);
    }
}

If we save the Script, press Play and fire the bird into the ice then it will now break:
Ice breaking

Now we can take a few minutes to duplicate the structures and position them on top of each other so we can add the pigs inbetween them later:
Structures Positioned

The Green Pigs

The birds want to destroy all the pigs, so let's add some pigs to our game so the birds don't get bored.

We will begin by drawing one:
Pixel Art Pig
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We used the following Import Settings for our pig:
Pig Import Settings

Afterwards we can drag it from the Project Area into the Scene and then select Add Component->Physics 2D->Circle Collider 2D and Rigidbody 2D:
Pig Physics in Inspector

The pigs are supposed to die if a huge enough force hits them. Luckily for us, we already have a Script for this. So let's select Add Component->Scripts->Break On Impact and assign a low Force Needed value to it:
Pig with Break on Impact Script in Inspector
Note: being able to re-use Scripts like this is what makes component based development so awesome.

Now we can duplicate the pig and move it in-between some structures:
Pigs Positioned in between Structures

If we press Play then we can now try to destroy the pigs:
Pigs ingame

The Rubber

We will add one last feature to our game: a rubber for the slingshot, so dragging and releasing the birds will look much better:
Rubber ingame

We will begin by drawing one half of a rubber, which is pretty much just a thick line:
Pixel Art Rubber
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

Here are the Import Settings:
Rubber Import Settings
Note: this time we set the Pivot to Right to make some rotations easier later on.

Now we can drag it from the Project Area into the Scene twice, name one of it leftRubber, the other one rightRubber and position them at the upper parts of our slingshot:
Rubber positioned

We want to make sure that the left one is always drawn behind the slingshot and the right one is always drawn in front of it. We could add two more Sorting Layers to our game, but we will keep it simple and just change the Order in Layer to -1 for the left rubber and to 1 for the right rubber:
Left Rubber Order in Inspector

Right Rubber Order in Inspector

Now the rubber looks like it's on the outside of the slingshot:
Rubber Order in Scene

Before we start Scripting, let's select the two rubber GameObjects in the Hierarchy and then move them into the slingshot GameObject so they are its children:
Rubber child of Slingshot
Note: now whenever we move the slingshot, the rubber parts will move with it.

Let's create a new C# Script and name it Rubber:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

The purpose of this Script is to make the two rubber parts follow the bird until it leaves the spawn's trigger circle.

We will need two variables that let us specify the rubbers later on. We won't need the Start or the Update function:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {
    // The Rubber objects
    public Transform leftRubber;
    public Transform rightRubber;
}

Now the slightly more complicated part. We will need a function that positions the right end of the rubber on the slingshot and the left end on the bird. There is no Unity function for this yet, so we will have to first rotate the rubber into the bird's direction and then make the rubber longer or shorter depending on how far away the bird is:

void adjustRubber(Transform bird, Transform rubber) {
    // Rotation
    Vector2 dir = rubber.position - bird.position;
    float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
    rubber.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

    // Length
    float dist = Vector3.Distance(bird.position, rubber.position);
    dist += bird.GetComponent<Collider2D>().bounds.extents.x;
    rubber.localScale = new Vector2(dist, 1);
}

Note: at first we calculate the direction from the bird to the rubber. Then we calculate the angle of this direction. Afterwards we set the rubber's rotation to that angle by using Quaternion.AngleAxis. Finally we use basic vector math to calculate the distance between the rubber and the bird. Afterwards we set the horizontal scale to that distance (plus half the width of the bird, which is bounds.extents.x).

The OnTriggerStay2D function will notify us whenever the bird changes its position while it is still in the slingshot. We can use this function to adjust the left and right rubber:

using UnityEngine;
using System.Collections;

public class Rubber : MonoBehaviour {
    // The Rubber objects
    public Transform leftRubber;
    public Transform rightRubber;

    void adjustRubber(Transform bird, Transform rubber) {
        // Rotation
        Vector2 dir = rubber.position - bird.position;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        rubber.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

        // Length
        float dist = Vector3.Distance(bird.position, rubber.position);
        dist += bird.GetComponent<Collider2D>().bounds.extents.x;
        rubber.localScale = new Vector2(dist, 1);
    }

    void OnTriggerStay2D(Collider2D coll) {
        // Stretch the Rubber between bird and slingshot
        adjustRubber(coll.transform, leftRubber);
        adjustRubber(coll.transform, rightRubber);
    }
}

Almost done. We will add one more mechanic that makes the rubber shorter after firing the bird:

void OnTriggerExit2D(Collider2D coll) {
    // Make the Rubber shorter
    leftRubber.localScale = new Vector2(0, 1);
    rightRubber.localScale = new Vector2(0, 1);
}

Now we can add the Script to our slingshot by first selecting the slingshot GameObject in the Hierarchy and then clicking on Add Component->Scripts->Rubber. We will also drag the two rubbers into their corresponding slots:
Rubber Script in Inspector

If we press Play then we can now see the rubber stretch between bird and slingshot:
Rubber ingame

Of course, now we can also play a round of Angry Birds:
Unity Angry Birds

Summary

We just created a nice little Angry Birds clone in Unity. There was a whole lot of stuff to learn. We used simple shapes and colors to achieve a nice visual effect. We made extensive use of Unity's 2D Physics system and added a whole lot of effects to our bird.

All these little tricks like breakable ice, a bird that spawns feathers when it collides with something and a trail that marks the trajectory are what makes the game feel right later on. This is why it's so important to keep the game small and focus on each little detail to make the game feel right.