< Return to Video

Unity 4.3 - 2D Game Development Walkthrough

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

more » « less
Video Language:
English
Duration:
28:22

English subtitles

Revisions