In Unity 4.3 we're launching our first set of 2D features.
To compliment this we have constructed a
demo project with these tools.
Our 2D platformer is nicknamed 'Tower Bridge Defence'
It depicts London's Tower Bridge in the midst
of an alien invasion.
It's a completely sprite-based, physics driven
2D sample level that we hope will help you
understand how 2D games are put together in Unity.
This video will discuss the background and
foreground construction, characters, effects,
camera tracking, animation and scripting
used in the demo.
To begin with, let's discuss the basics
of working in 2D in Unity.
Firstly, when working in 2D, you should set the
Editor Behaviour Mode to 2D
for various settings.
This can be done when making a new project
using the drop-down on the project wizard
or during a project by choosing
Edit - Project Settings - Editor from the top menu.
This means that by default textures
will be imported as sprites and the
Scene View will default to 2D mode.
This new mode gives you a completely orthographic
view in which to construct 2D games.
It also hides the usual 3D gizmo
in the top right of the view, giving you more space
to work in. Aside from these settings the work
flows for 2D have been designed to mirror
existing Unity approaches to 3D game creation.
So if you already know a little about Unity
you'll be in a great position to start making
2D games right away.
It's worth noting at this stage that you can
still mix 2D and 3D in Unity,
so if you want to add 3D elements to your 2D game
or vice versa you can do that with no worries.
Let's take a look at the demo project itself,
and how we built it up one stage at a time.
We began by sketching out the level design
for this sample level and then went about
recreating the layout in Photoshop.
Creating and exporting the layers,
we were able to import these in to Unity
using the new Sprite type.
In order to create parallaxing in our background later,
we kept some of the background elements separate
and placed them on to a Background Sorting Layer.
Yet another new feature of 2D development in Unity.
Having assigned all of our backgrounds to this layer,
we could then use the Order In Layer property
of the Sprite Renderer to sort them.
Once we were happy with their positions
we could lock the Background Sorting Layer
so that when we added foreground elements
we didn't need to worry about accidentally
dragging background elements around.
This is done using the Layers pull-down in the
top right of the interface.
Because the background elements are purely decorative
we did not require any additional components
on the sprite game object.
They were parented to an empty game object
that has a simple script to handle parallaxing
called BackgroundParallax.
For more information you'll find this script
fully commented in the Scripts folder.
Next up came the creation of the foreground elements
that our characters would actually traverse.
We designed London's Tower Bridge with a UFO
landed in the centre.
The character has the run of the environment
as enemies spawn from the skies and begin
to navigate around the level.
As such, each piece of the foreground required
a collider for characters to walk upon.
For most of the environment we used 2D
box colliders for efficiency,
but the UFO itself has a more complex shape.
Unity's Polygon Collider allowed us to
automate creation of the collider itself
based on the shape of the sprite.
It even meant that we could tweak the shape of
the collider later.
Moving, adding or subtracting points
of the collider shape to make it more
appropriate to walk over.
To sort these foregrounds we created a
Foregrounds Sorting Layer, which was drawn
above the backgrounds in the Tags And Layers manager.
Next, let's take a look at our hero.
Our player character was yet again designed
in Photoshop, and for this demo
we chose to make a character with independent
limbs and features in the style of
2D hits such as Rayman.
Our other option would have been to design
a sprite sheet-based animation and design each
each frame in Photoshop,
an approach we use later for the background Swan,
which we'll discuss later in the video.
Because our character had independent elements
that we wish to animate we finalised the design
and then moved his bodily elements in to separate
spaces on our canvas to allow Unity to isolate them
as separate sprites in the Importer.
This meant that we could then arrange all of
our sprites as separate elements to be animated.
We placed these on to a new Character Sorting Layer
that we created, and then used Z values in the
transform to sort their rendering depth.
All of these sprites are then arranged under an
empty game object, which has all of our
controls scripting, colliders, physics, excetera attached to it.
Once we'd done this we were able to use the newly
upgraded Animation window to create
Idle, Run, Jump, Shoot and Death animations
by animating each of the character's sprites over time.
With the new Dopesheet View in the Animation window
this is easier than ever.
We simply add animation to the parent object
and then create keyframes for any of the child objects.
Moving the playhead to where we want
and then moving the various parts of the character
to automatically keyframe the animation.
The ability to switch between Curve and Dopesheet
representation of our animation makes it easier than
ever to adjust timing and design.
With these animations created we can
then design a state machine for our character
so that when called upon in code, differing animations
could be played.
the animator controller for the character is
not driving a 3D biped, so we simply deselect
Apply Root Motion and select Animate Physics
in order to drive our animations in time with
the physics engine.
In order to traverse the environment our hero has a
circle collider at his feet and a box collider
to cover the rest of his body outline.
This means he can smoothly walk up and down hills
and when he jumps his head will hit the ceiling.
In order to control the character and it's animations
we wrote a script that moves him via 2D physics forces.
This means that we can apply physics to him
and the enemies during the game for more
dynamic game play.
In our PlayerControl script for the character
we check for player input.
We use this to apply physics forces
for movement and also send the value of the input
to the animator, which in turn defines which
animation should be playing and smoothly transitions
between the different animation clips that
we've created as states.
The great thing about using the animator to
create states from animation clips is
that we can go and tweak speeds of animation
to match our physics velocities
without having to reanimate anything
The FixedUpdate function evaluates with
each physics step, and the first thing we
do with this is to feed the value of Horizontal
input in to the Speed parameter of our animator.
The transition between Idle and Run
in our simple state machine requires
that the Speed parameter is above 0.1.
When it is, the animator blends from Idle
in to the Run state.
We then go on to add forces to the player's
2D physics component, the rigidbody2D,
in order to move him around.
We also handle which direction the character is facing
based on the value of Horizontal input,
checking whether it is above or below 0.
This is because in Unity, holding the left input key
returns a value of -1, where right returns positive 1.
Depending on input, we then call a simple flip function,
which reverses the X scale of the character,
giving him the appearance of facing the opposite direction.
To decide whether the player is grounded
we added a layer in Unity called Ground
and applied it to all of our walkable foreground surfaces.
We then used the Linecast function in 2D
to check whether something on the Ground layer
is below the character's feet.
To customise this more easily we created
an empty game object to use as a point
at which to check for the ground.
By adding a gizmo to this empty object
we are able to manipulate how far below
the character we'll check for the ground.
From a gameplay perspective this means that
the character can only jump when grounded.
Check out the rest of the comments in the script for more
information on the control of the player.
We will discuss the player's weapon
later in this video.
Next, let's take a look at how the camera
tracks the player in our demo.
In 2D games, much like 3D, the motion of
the camera tracking the action can make
or break your game.
For a classic 2D platformer, we looked at the mechanics
of one of the most interesting camera in 2D gaming history,
the camera from Super Mario World on the Super Nintendo
or Super Famicom.
In Super Mario world the camera tracks
horizontally, but uses a dead zone
or margin in the centre of the viewport
in which the character can move a little
without the camera tracking.
Once the character moved beyond this margin
the camera tracks back toward the player.
The Super Mario World camera used particular heights
to snap to vertically, but we didn't need this
kind of detail for our game as we
do not have a long level in the X axis
but more of a stage on which the action takes place.
For this reason our camera employs
similar tracking vertically as it does horizontally.
Take a look at the CameraFollow script on the
mainCamera game object to see comments
on how it achieves this effect.
There are several effects in the game,
but most important is our heroes ability
to slay the alien onslaught he's faced with.
Our hero shoots a bazooka which has animated recoil.
This action is made up of several parts.
First we listen for key input and when the Fire key is
pressed we instantiate a rocket,
play an audio clip and trigger an animation state to play.
Let's break this down even further.
in order to play the Shoot animation while other
animations such as Run are playing we
created a separate layer within our animator
called Shooting.
By setting the Weight property to 1 here
we can totally override motion in the base layer
on any parts of our character that are animated
by clips on the shooting layer.
In this layer we switch to the Shoot animation
from any state, when the Shoot trigger
parameter is called from code.
Let's take a look at the Gun script in charge of this.
Here you can see that we address the animator
and set that trigger to True.
Triggers simply act as a switch and reset themselves to false
on the next frame so that they can be called again,
which is perfect for actions such as shooting.
In addition to setting the animation we fire the
rockets themselves from this script,
playing an audio clip and dependent upon
the direction that the player is facing
we instantiate a rocket and give it a velocity
that's positive or negative in the X axis.
This script is attached to the Gun empty game object
in the hero's hierarchy.
We place code like this on to an empty game object
as it allows us to easily position
where the rockets are created.
We do this by placing the empty object
at the end of the barrel of the bazooka
and then we use it's own position as the
point at which to spawn the rockets.
The rocket itself has a 2D rigidbody
and we assign a velocity to that in order
to make it move.
It has a sprite swap flame exhaust
plus a particle system for smoke.
The particle system also accepts the new sprite type of graphics
so by adding a sprite sheet of smoke puffs
to a material we can assign it to the
texture sheet animation module of the particle system
and we get instant animation of our
sprites for the particle emission.
When our rockets hit an enemy or part of the environment
the rocket itself is destroyed and
an explosion is spawned.
The explosion is simply a sprite game object
that animates through a sprite sheet that we have created.
Yet again using sorting layers to render this
at the lowest layer order of our foreground objects.
When adding sprite-based animation like this
we setup the sprites themselves by
selecting the file in our Project Panel
and choosing the Sprite Mode Multiple.
This gives us access to the sprite editor
which allows us to slice manually or automatically.
Once happy with the selection of sprites from our file
we simply hit Apply and Unity
generates the sprites as children of that file
to be used in our project.
So that's our rocket in a nutshell.
We will discuss the mechanics of killing the enemies
later in this video in the section about enemies.
Let's return to the player character now and look at
how we handle health and taking damage.
Health is stored as a float and
with each interaction with a tagged enemy
we call the TakeDamage function.
This is only allowed to occur after the
repeatDamagePeriod has passed
to avoid the player being killed very quickly.
To allow the player to escape enemies more easily
and to show the player that they are being hurt
we make the act of taking damage
repel the character physically.
To achieve this the TakeDamage function briefly
stops the player from jumping
and finds a vector from the enemy to the player
and repels him in that direction
by adding a physics force.
The hurtForce variable is exposed in the Inspector
as public so that it can be tweaked
to adjust this element of game play without
returning to the script.
In addition to repelling the player,
we of course subtract from the player's health.
and update the player's health bar.
To signify the decrease in health we subtract
from the width of the bar and use a colour lerp
to transition it's colour between green and red,
both by finding the percentage that the current health is
of the full health amount.
The health bar simply comprises of two sprites,
one for the outline of the bar and the other
for the bar itself.
This was again designed in Photoshop and then
the two separate elements were exported.
In the import settings for these sprites
we set their pivot to the middle left of the graphic
so that when it scales down it shrinks towards the left.
These two sprites are placed under an empty
parent game object which has a simple script
on it which makes it follow the player.
We do this by setting the position to the
same as the player object's position
plus an offset that we've made public to allow
for adjustment in the Inspector.
When the player has 0 health remaining
we allow him to fall through the level by
setting his colliders to triggers,
and we move him to the very front of rendering
by placing his sprite renderers on the UI Sorting layer,
one we've made to render in front of everything in the game.
We have 2 animations for when the player dies.
1 called Death, where he loses his hat and gun
and another called Falling.
We naturally transition in to Falling once
the Death animation completes by using the Exit Time
as our transition condition in the animator.
Finally, to stop the player moving the character
or shooting during the Death sequence
we disable the PlayerControl and Gun scripts.
Because the Die function is made as public
we can call it from elsewhere, such as if the player
falls in to the water.
To reset the game once the player does hit the water
we have a KillTrigger object, which simply
comprises of a trigger collider and a script.
For most of the game the purpose of the Remover script
is to remove our enemy objects that fall in
to the river, and instantiate a splash animation
and sound effect.
However, when the player is detected by this trigger
we call the Die function in the PlayerHealth script
and also disable CameraTracking
whilst moving the player off screen
and calling a co-routiene that pauses for 2 seconds
and then reloads the level.
But let's not dwell on the death of the player,
let's look at his survival and the tools that we give
him to do that.
Our game features 2 airdropped crates that
assist the player, 1 containing a bomb,
the other a med kit to boost health.
These crate drops are made up of 2 parts.
The crate itself and a parachute.
These 2 elements are nested beneath an empty parent object
to allow us to animate them as a group.
We position the 2 sprites so that the parachute's
centre is at the centre of the parent.
This way the animation can swing left and right
as if the entire parachuting crate is floating to the ground.
We then simply add a rigidbody to cause
gravity to pull the object down
and add colliders to the crate so that
we can detect when it lands and when
the player picks up the crate.
Upon landing we transition to a second
animation state which scales the parachute down.
Like other parts of our game, the animator handles
the states of the object.
We can see that by default it plays the
floatDown animation state
but then switches to a landing state
when the trigger Land is set to true.
In our script we do this using an onTriggerEnter function,
which detects the ground via a tag.
We also detatch the crate itself from the parent object
and give it a rigidbody of it's own
so that it can interact with the environment
resting realistically on a slope if it lands on one.
Let's focus on the bomb first of all.
Picking up the bomb crate is handled on the
BombPickup script, attached to the crate.
We pickup the crate by destroying it and adding to
the count of bombs that the player has
in the script attached to the player called
LayBombs
The LayBombs script simply checks if
the player is carrying a bomb
and then instantiates an instance
of the Bomb prefab.
The Bomb prefab has a timed fuse
which waits by using an yield within the
BombDetonation co-routiene
before calling the Explode function.
The Explode function performs several actions.
First it resets the bombLaid variable
to allow another bomb to be deployed,
it tells the pickup spawner it is allowed to
spawn a new crate drop and kills
enemies within a defined blast radian.
Let's take a look at how this last part works.
Because bombs are lethal to enemies regardless of
their remaining hit points we use the
Physics.OverlapCircleAll to collect all objects
tagged Enemy within a certain radius of the bomb.
We then run a foreach loop for every enemy found
setting their health to 0 finding a vector from where the bomb was
to where the enemy is, in order to apply
a force in the direction of that vector.
Once the foreach loop is complete
we play and instantiate visual effects,
play an audio clip for the explosion
and of course destroy the bomb itself.
The visual of the explosion is twofold.
The main part is a simple circle that appears
briefly and is then destroyed
and the second part is a particle system of
stars that reuses the same sprites
as our rocket explosion.
For efficiency we keep this particle
system in the scene at all times
and when it is required we use code
to move the system to the desired position and play it.
This keeps the particle system in memory
and makes the game more efficient.
It's worth noting that we can do this
because we know we will only have 1
single explosion in the scene at any one time
as the player can only throw 1 bomb at a time.
This is why keeping our particle system in the
scene and replaying it is more
efficient than creating instances and then removing them.
With the rocket explosion however,
we can have many at once so we do
need to spawn and remove them.
Now let's take a look at what happens when our player
kills an enemy and scores points.
This is done in 2 parts,
a scoring animation that plays showing 100 points earned
and the score UI at the top of the screen
that increments.
The score animation is made up to 2 number sprites,
a 1 and a 0.
We place this in the scene under an empty parent object
and animated them using a simple destroyer script to
remove them from the scene when the animation is complete.
We call the destroyer function in the script
by placing an animation event
at the end of the timeline.
The ScoreUI itself is a simple GUI text component
with a custom font and script that manages
the score for the player.
The Score variable is public, meaning that we can address it
from the Enemy script when they are killed
and add 100 points to the value.
Speaking of the enemies, let's take a look
at them more in depth now.
In our game we have 2 types of alien enemy,
a green slug-like monster and a smarter
alien that brought his ship with him for
protection during the invasion.
These characters share the same script
as the behaviour is very similar
and we allow for differing movement speeds
and amounts of hit points by setting
these as public variables in the Inspector.
Each enemy has it's own Walk animation.
The slug has a moving tail, whist the
ship-based enemy rocks back and forth as it approaches.
For the slug we used the sprite importer
to define the tail section of the graphic
as a separate sprite element,
meaning that we could animate it individually
and avoid having to scale the entire sprite.
By setting the pivot to the right
we are able to animate the tail expanding and contracting
from that point.
For added character we then move the eyelid up and down
and we use the Z value to sort the sprites
amongst one another, the eye being below the eyelid
so that we could animate it over the top.
The second enemy's animation was much simpler
and just meant that we rotated it back and forth.
For the mechanics of moving the enemies
we drive them by setting the velocity of the rigidbody.
When they encounter an obstacle such as a wall
they detect this by using a Physics.OverlapPoint function,
which checks for a point in space overlapping a collider.
Our walls, the towers at each side of the level,
are tagged as obstacles.
When this function detects them it calls the Flip function,
it reverses the X scale of the enemy
sending them moving in a different direction.
To kill the enemies, each time a rocket collides
with them it's script calls the Hurt function on
the particular enemy that it's hit.
In this function we subtract 1 from the
hit points of the particular enemy.
We then keep tabs on the enemy's health
inside the fixed update function.
If it drops to 0 we call the Death function.
When they die we perform a number of functions.
Firstly we disable all sprite renderers
as our 2D characters are made up of a
number of sprite objects that are animated.
This is because we simply want to swap out the
animated elements for a single sprite
of the dead character
We do this with the main sprite renderer by
setting it to use the sprite assigned to
the deadEnemy variable.
We then add to the score using the public
variable in the Score script
and we add some visual flare to the enemy's death
by adding torque to spin them as they die.
Because we need the enemies to fall through the
environment and land in the river when they die
we find all colliders on the object
and set their IsTrigger parameter to true.
This means that they will pass through the
environment colliders.
We then choose from an array of death audio clips
and play one of them back, before creating
an instance of the Score animation we showed you earlier.
To remove the dead enemy from the scene
we rely on the killTrigger object
It performs the same function as discussed earlier
as any non-player object touching it
will cause a splash animation and remove that object.
The sound effect of them hitting the water is
an audio clip attached to the animated
splash which plays on awake
so that when we create an instance of the animated
object we hear the sound right away.
To finish the game level re decorated the
background with a number of moving props
in order to make our game environment feel more dynamic.
We added flying swans, plus buses and taxis that drive
along the river bank.
First was the swan, which was created from a sprite sheet,
drawn in Photoshop and imported using
the Multiple Sprite Mode import setting
in the Inspector.
By choosing this approach Unity automates choosing
each frame in the sheet and importing
it as a separate sprite under the parent
hierarchy of the asset.
Because this is a linear set of animation frames
we could simply drag all of these sprites in to the
scene to let Unity animate them for us.
Et voila, our animated swan is ready to add
as a background element.
The swan was then given a rigidbody2D
so that we can use velocity to send it
across the screen.
As with the bus and the cab, the swan is saved as a prefab.
For the bus and taxi prefabs we
simply separated the bodies and wheels of
the vehicles in the sprite importer
and made a simple bobbing animation.
Applying a 2d rigidbody to these as well,
we were able to drive them across the screen
using velocity.
For all 3 props, the bus, taxi and the swan
we created a script we could reuse
which is in charge of spawning them.
The BackgroundPropsSpawner script
also handles the frequency, a speed to give them
and where on screen to spawn them.
This meant that we could make 3 creator objects
with the same script on.
Changing which prefab will be spawned
and what properties to give it.
Take a look at the comments in the script to learn more.
Finally, for more background dynamism,
we added rolling clouds, panning river details and fog.
We did this by adding 2 instances of the background sprite
to a parent object and simply used animation to slowly
pan them across the screen.
Because this animation loops our animation will
continue indefinitely.
And that's how we made our game.
We hope this overview has given you some idea of
how we create 2D games in Unity,
and we'll be creating more simply projects and
tutorials in the future.
We look forward to your feedback on Unity4.3
and we can't wait to see the great 2D titles
that you'll come up with.
Thanks for watching.