にゃごすwiki

unity2dGamePlay_2

The 2D Platformer Scene.
Controls
Use the cursor keys to move Lerpz. Hold down the Ctrl key to make him run and use
the space bar to jump.
The GUI buttons at the top toggle between controlling the character and the spaceship.
Everything in this scene has already been laid out for you. Feel free to explore
and examine everything you can. The more familiar you are with how we set up our
level, the easier it will be to create your own.
A Closer Look
Here are two things you can investigate to better understand how to set up a 2D
game before you do it yourself:
Object Positions
If you bring up an element in the Inspector, you’ll see that all objects are placed at
zero in the Zaxis,
keeping to the convention we defined above.
When modeling your 3D assets, it may make your life easier to model them in your
modeling application with the same orientation as in Unity. Although not crucial, this
avoids the inconvenience of having to rotate them after you import them.
Platform Tiling
If you investigate the platforms in this scene you'll notice that they are made up of
smaller, tileable
pieces, with endcaps
for the beginnings and ends of platforms. This
can save hours of modeling time so platforms can be built within Unity and easily
changed. Everything from the size to the textures are modeled with tiling in mind.
9
NOTE Tiling was a very common technique in the early days of computer games. It
had the very useful advantage of reducing the amount of graphical assets required,
keeping the project’s overall size down. In the days when computer
memory was measured in kilobytes, this was an important factor. Today, tiling
remains a useful technique as it reduces both asset production time and download
size.
Setting the Level Attributes
After playing our prebuilt
level, it's time to begin our own.
Create a new scene by going to File>
New. You now have a completely empty scene
that is ready to rock. Before you begin, make sure that your interface is set up how
you prefer. Be sure that the Scene View, Project Pane, Hierarchy Pane, and Inspector
are all present.
First thing to do is to define our Skybox:
Go to Edit>
Render Settings in the menu. In the Inspector, you should see an
empty slot for a Skybox.
In the Project Pane, expand the folder Standard Assets>
Skyboxes.
Drag Martian Stratosphere into the Skybox Material slot in the Inspector for the
Render Settings.
The Render Settings
Now we should have a nifty skybox that we will see in the background at all times in
our game.
10
The Game View, showing the Skybox.
Next, we need to add something which will manage some important attributes.
Look in the Project Pane and find the Prefab named Level Attributes within the
Level Prefabs folder.
Drag the Prefab into the Hierarchy Pane so it is loaded in your scene.
Ensure that its Position is at (0, 0, 0). This will make life easier in the long run for
the child object "Death Zone."
The Level Attributes Prefab in the Scene View. We see two new objects here: the small rectangle rising upwards
defines the level’s boundaries. The long oblong lying flat is the “Death Zone” (displaying the skull).
11
In the Scene View you should now be able to see a green rectangle that represents the
size of your level. If you cannot see the green rectangle, adjust your viewing position
so that you can clearly see it.
Adjust the settings according to how big you want your level to be.
As a reference point, the completed level that we supplied was 44.25 units wide
by 60 units tall. Make sure that everything is located at zero in the Zaxis.
The
size of your level can easily be changed later so don’t worry about getting it absolutely
right.
Finally...
SAVE your scene!
So what’s going on here? Lets take a much closer look at the Level Attributes and
Death Zone GameObjects...
Object Profile: Level Attributes
The Level Attributes object started as an empty GameObject at position (0, 0, 0). The
script LevelAttributes has been applied to it.
Functions
• OnDrawGizmos()
Displays the level’s dimensions. The level’s size is denoted by the greenbordered
rectangle
drawn in the scene view.
• Start()
Creates physics Colliders at startup that act as borders around the world to prevent
the character from leaving the level boundaries.
Script: LevelAttributes
This script defines the level’s key attributes based on the values you set in the Inspector:
• Bounds
‣ X: The xcoordinate
that your level will start at.
‣ Y: The ycoordinate
that your level will start at.
‣ Width: The width of your level starting at the Xcoordinate
above.
‣ Height: The height of your level starting at the Ycoordinate
above.
12
• Fall Out Buffer: This creates a buffer zone at the bottom of your level. Its purpose is
to give your character some room to fall without the camera following until it hits the
bottom Collider.
• Collider Thickness: The thickness of the Colliders that create your borders.
Further Analysis
If you select the LevelAttributes GameObject after pressing play, then look at the
green boundary rectangle in the scene view, you will notice Colliders (represented by
light green boxes) at the edges. These are the automaticallygenerated
physics Colliders
created by the LevelAttributes script.
Object Profile: Death Zone
The Death Zone object started as an empty GameObject at position (0, 0, 0). It is a
child object of Level Attributes. It does not need to be a child of Level Attributes, but
for organizational purposes works well there. The script "DeathTrigger" has been applied
to it.
Function
Provides a Collider defined
as a Trigger which
causes the character to respawn
if
he/she falls onto it. This is useful for pits that the player can fall into.
Script: DeathTrigger
This script draws the little skull and crossbones that you see in the scene view by taking
advantage of Gizmo icons. Although it's not necessary, it is useful. (“Setting Up
the Platforms” has more information on Gizmos.)
Setting Up the Platforms
Now it's time to create the foundation of our level: the platforms.
In the Project Pane you will see a prefab called "PreAssembled
Platform." Drag
it into the Scene.
Ensure the platform is located at zero along the zaxis.
Position the platform in a place you're happy with.
13
Placing the PreAssembled
Platform Prefab.
This platform was preassembled
for you, but you will have to make the rest yourself.
Look in the Hierarchy Pane and you'll see that the PreAssembled
Platform has several
child objects. These children objects are what make up the platform. If you investigate
the platforms you'll notice that they are made up of smaller, tileable
pieces, with
endcaps
for the beginnings and ends:
Looking inside the PreAssembled
Platform Prefab.
Using these platform tiles, create more platforms for your character to run wild!
Keep these pointers in mind:
• Always make sure the zposition
is at zero.
• Look at the preassembled
platform for reference.
14
• We highly recommend that you parent groups of platform tiles together, for reasons
described in Object Profile: PreAssembled
Platform, below.
To do this, create an empty GameObject by going to GameObject>
Create Empty and
name it appropriately. Make sure the GameObject is located at zero along the Zaxis.
Also make sure that the X and Y coordinates are where you want the platform to be
located. Then you can drag the platform tiles inside the empty GameObject you just
created. Last, apply the script CombineChildren so you mimic the function of the PreAssembled
Platform GameObject described above.
• The tiles can be precisely positioned easily because their lengths are nice wholenumber
values.
• The platforms must stay inside of the green level boundary you set up in the previous
section! If your platforms are outside this area they will be unreachable. You can always
change the size of the boundaries.
• Save frequently!
You can always create more platforms later, but you at least want an area that the
character can run around.
Object Profile: Platform (Prefabs)
In the Project Pane you can find these prefabs inside Level Prefabs/Platforms.
Functions
These are the tileable
pieces that make up the larger platforms. You'll find five different
pieces within the Platform Tiles folder:
• Platform Level:
A level piece of platform that is 6 units long.
• Platform Slope
Up:
A piece of platform that slopes up moving from left to right. It is 3 units long.
• Platform Slope
Down:
A piece of platform that slopes down moving from left to right. It is 3 units long.
• Platform End
Cap Left:
This belongs at the left edge of an array of platforms to cap it off.
• Platform End
Cap Right:
This belongs at the right edge of an array of platforms to cap it off.
15
The length of these pieces, (with the exception of the end caps since it is not necessary,)
are nice whole numbers so they can be precisely tiled by editing the numbers in
the Inspector.
Components
• Box Collider
Without this, the character and spaceship would fall right through the platform! This
is needed to physically interact with the character. The Box Collider size has been adjusted
to fit the platform tile, otherwise all settings are default. Since the platform
does not move at all, we do not have to apply a Rigidbody component.
• Pipeline, Mesh Filter, and Material:
These assign the proper mesh and texture so it renders in the scene.
Script: CollisionSoundEffect
The foot script attached to our player checks GameObject it comes into contact with
for the presence of this script and plays the sound effect it holds (if you have set one).
In this way our player character’s footsteps can be made to sound different on different
surfaces e.
g. a metallic sound on metal platforms; a wooden footstep sound on
wooden surfaces, and so on.
Script: CollisionParticleEffect
This script, like the one above, provides a similar service for particle effects. The
player’s foot script looks to see if we’ve set a particle effect GameObject and starts it if
so. This is how the character raises the clouds of dust as he runs around the example
level.
TIP If you're curious, examine the texture (which is the same for each tile) to see
how it loops.
Object Profile: PreAssembled
Platform
It's the parent object that contains platform tiles that create a single large platform.
Function:
This GameObject serves two purposes.
• As a container used to organize the level and
• To aid performance see
the script described below.
It is recommended that you structure your entire level using this method. In other
words, for each group of platform tiles that make up a large platform, create a parent
object for them with the CombineChildren script applied.
16
Script: CombineChildren
In the Inspector you can see this script with its selfexplanatory
options. What this does
is take all of the children GameObjects i.
e. the platform tiles and
combine their
meshes so instead of rendering 6 different objects, only 1 object is rendered. This enhances
performance, especially when you reach a large number of platforms.
TIP This script actually comes in the Standard Assets package, which is shipped
with Unity.
Introducing Lerpz, Our Lovely Character
Lerpz, our zany character, is getting anxious for action!
Lets get our spawn point set up first. The spawn point is where the character will appear
when you start the game. It's pretty simple to do, just follow these steps:
Create a new empty GameObject by going to GameObject>
Create Empty. Rename
it to “Character Spawn Point”.
17
Apply the script titled SpawnPoint to the GameObject you just created. This
script creates that little 2D icon of Lerpz inside the Scene View so you can see
where the spawn point is. (This little drawing is called a Gizmo. The Death Zone
also has one of these to display the skullandcrossbones
icon.)
Position the spawn point where you want Lerpz to appear. Make sure it is at z =
0 with a platform underfoot, so he actually has a place to stand when he appears.
What exactly is a Gizmo?
Gizmos are shapes, icons and other visual aids that appear in the Scene View such as
lines, lamps, cameras, and audio sources to assist in visual debugging or layout. Gizmos
drawn exclusively in this 2D tutorial are the Death Zone, and Character Spawn
Point.
All it takes is a very simple script. Here's an example of the script SpawnPoint that is
applied to the Character Spawn Point:
function OnDrawGizmos()
{
Gizmos.DrawIcon(transform.position, "Player Icon.tif");
}
Gizmo icons must be placed in the Assets/Gizmos folder.
The LevelAttributes script also takes advantage of Gizmos: The green border you see
representing the level boundaries is a Gizmo. For a complete reference on Gizmos, you
can refer to the documentation
(http://unity3d.com/Documentation/ScriptReference/Gizmos.html).
Placing Lerpz
The next step is to add Lerpz himself to our Scene:
Drag the Prefab "Character (Lerpz)" in our Level Prefabs directory into the
Scene. Since we have a spawn point set up, you can place him anywhere you'd
like, just as long as he's somewhere in the Scene.
If it’s not already visible, bring up our Character in the Inspector and open up
the Platform Controller Script Component. Note the Spawn Point slot:
18
Character (Lerpz) with no Spawn Point set.
Drag our earlier Character Spawn Point object into this slot, so it looks like this:
Character (Lerpz) with the Spawn Point set.
The next step is to get the Main Camera to follow Lerpz around...
Directing the Camera
At the moment, our main camera will simply sit where it is and point at whatever it’s
aimed at. Much like in a movie or TV production, we need to direct the camera tell
it how to move, when to do so and what it should be aimed at. We achieve this with
two scripts:
Drop the CameraScrolling script (from Scripts>
2D>
Camera) onto the Main
Camera GameObject.
Drop the CameraFocus script (from the same location) onto the Main Camera.
The next step is to give the scripts the information they need to work:
Select the Main Camera in the Hierarchy Pane and open up the CameraFocus
script Component in the Inspector.
Open the Targets group and change Size to 1. Element 0 should appear below it.
Drag our Character (Lerpz) GameObject onto the Element 0 slot.
Open the Target Button Names group and change Size to 1. (Again, Element 0
should appear.)
Type “Player” into Element 0’s slot.
19
The result should look like the image below:
Setting up the Camera Focus script component.
We should now have a working camera and character running and jumping over our
platforms.
It was very easy to get the character in the level using Prefabs, but on closer inspection
Lerpz is anything but simple:
Object Profile: Character (Lerpz)
Lerpz is the main character of our game. He can walk, run, jump, and fall. He moves
around our level wreaking havoc wherever he goes.
Components
• Animation
This component stores a list of animations for the character that can be accessed by
scripting. PlatformPlayerAnimation (listed below) makes use of this component by accessing
different animations.
• Character Controller
The traditional sidescrolling
character controls are generally not physically realistic.
The character comes to a halt immediately and turns on a dime, making it difficult and
impractical to use Rigidbody physics. As a result, we use an alternate method to move
the character around by using the Character Controller. See more detail on this component
in the documentation.
(http://unity3d.com/Documentation/Components/classCharacterController.
html)
Script Applied: PlatformerController
This script is a custom script made for this 2D tutorial. This script, in cooperation with
the CharacterController component, is used to define its physical mechanics within our
world. Most of the adjustable settings are selfexplanatory
and we will not go into
much detail, but a few require some further discussion:
20
• Speed Smoothing
How quickly does the character change speeds? For example, how quickly can the
character go from not moving to running. Higher means faster.
• Rotation Smoothing
How fast the character visually changes directions. It does not affect the motion.
• Can Control
This simply states whether the player can control the character. This can be turned off
by another script if at any time you want user to lose or gain character control. An example
of this being toggled is when you toggle between the spaceship and the player.
• Spawn Point
You must define the spawn point by dragging a Transform object into the slot. Then
the character will spawn at that point.
Script: PlatformerPlayerAnimation
This script takes the animations listed in the Animation Component and plays them at
the appropriate times. For example it detects when a player is on the ground and
moving at a certain speed, and then plays the appropriate animation such as "run."
Script: PlatformerPushBodies
Since the character is not a Rigidbody, it does not automatically physically interact
with everything around it. This script allows the character to apply forces to Rigidbodies
such as the crates within the level.
The setting Push Power is the strength of the push applied by the character.
The Push Layers setting determines what layers the character can actually push. Sometimes,
you may not want a specific Rigidbody to be pushed by the character but still
interact physically with the world around it, so you can create a layer for that object
make sure that the character cannot push that layer with this setting.
Script: CameraTargetAttribute
This defines some camera behaviors, and is also applied to the Spaceship. This script is
more thoroughly discussed in the next section.
Further Analysis
We have just scratched the surface of explaining the character. To fully benefit you, it
would be wise to examine and experiment with all of the scripts attached to the character
to see how they work. We have supplied comments in the code to help guide
you along.
Take a few moments to play around with Lerpz's settings. Adjust the different settings
to see what they do, and if things get too crazy you can always delete him from the
scene and add a new one using the Prefab!
21
Lighting our Scene
At this stage we have our character running around our Scene, but it’s all very dark.
We need some lights to make everything easier on the eye!
We’ll add two Directional Lights:
Create an Empty GameObject. Name it “Main Lights”. (We’ll use this to organize
our lights and keep them in one place.)
Create a Directional Light. (GameObject>
Create Other>
Directional Light).
Rename it “Downlight”.
Drag the light into our Main Lights object.
Rotate our Downlight
object to point about 60 degrees downwards.
Set it as shown below (Intensity is also changed from the default, to 0.5):
The light blue downlight’s
settings.
Now we’ll repeat the process again, but for our uplighter.
This will light the undersides
of the platforms:
Create a Directional Light. (GameObject>
Create Other>
Directional Light).
Rename it “Uplight”.
Drag the light into our Main Lights object.
Rotate our Uplight
to point about 60 degrees upwards.
Set it as shown below (Intensity is again changed from the default, to 0.5):
22
Color Red Green Blue Opacity
Light 184 233 255 100
The purple uplight’s
settings.
The next step is purely for our own convenience:
Select our Main Lights parent object and drag it backwards, away from the platforms
(see screenshot below). Precision isn’t important here: this is just to keep
the lights out of the way while we work as
they’re Directional Lights, their
distance from the platforms has no effect.
Our completed lighting rig should look something like this, (although your level’s
platforms will probably be very different):
Our lights, positioned away from our Camera and level, so we can see them more clearly. The “Main Lights”
object is highlighted here, showing both the child lights.
TIP The light colors chosen in this example are hardly subtle, but they clearly show
how each light affects the scenery. Feel free to change the colors!
23
Color Red Green Blue Opacity
Light 238 71 255 100
Spicing up the Character
Lerpz has a couple of simple visual touches: a working jetpack
and dust clouds kicked
up when he walks. Let’s look at these in more detail:
Jet Pack Particle Effects
If you watch the character's jet pack it only fires when he jumps and is moving upwards.
Additional scripting is needed to accomplish this. We also need to make some
particle effects.
In the Hierarchy Pane, expand the Character, then expand rootJoint and lastly
expand torso. Here you will see where the Rocket Jet GameObjects are located.
The code to start the jets is inside the PlatformerController script within the Update()
function.
TIP Unity’s Particle System features are covered in depth in our Resources area.
Check out Forest “Yoggy” Johnson’s video on the subject, as well as our 3D
Platformer Tutorial.
Footsteps in the dust
As Lerpz walks, we hear his footsteps and see him kicking up plenty of dust. (Clearly
it’s been some time since these platforms were given a good clean!)
If you expand the many levels of Lerpz's legs in the Hierarchy Pane, you'll notice that
each foot has a FootEffect GameObject attached to it. This contains three Components
and a script:
• RigidBody
This component is required if we want Unity to detect collisions.
• AudioSource
Essentially a placeholder for a footstep sound. When our script detects that our foot
has struck another object, it checks if that object has a CollisionSoundEffect script. If it
does, it grabs that sound effect, drops it into this AudioSource component and plays
it, adding a subtle, random variation to the pitch each time for variety.
• Sphere Collider
Unity’s physics engine uses this to determine when the foot has touched something.
This is set as a trigger. When this Collider touches the collider in a platform object, the
foot script reacts accordingly by scanning the object we’ve struck for CollisionSoundEffect
(see above) and CollisionParticleEffect scripts, playing the relevant effects accordingly.
The foot script does nothing other than the tasks mentioned above and is therefore
very short and simple:
24
var baseFootAudioVolume = 1.0;
var soundEffectPitchRandomness = 0.05;
These two variables define the volume of the footstep sound effect, as well as how
much variation is applied to its pitch. (This variation is used to prevent the footstep
sounding too artificial.)
The first function we define is OnTriggerEnter(). This is called whenever the
Sphere Collider touches another Collider, such as that attached to a platform element:
function OnTriggerEnter (other : Collider) {
var collisionParticleEffect : CollisionParticleEffect =
other.GetComponent(CollisionParticleEffect);
if (collisionParticleEffect) {
Instantiate(collisionParticleEffect.effect, transform.position, transform.rotation);
}
The above code looks for a CollisionParticleEffect script in the object we’ve collided
with. If it finds one, it fetches the particle system Prefab we’ve stored in there and instantiates
it at the foot’s position. This is how we produce the little clouds of dust.
The next section of code does something very similar for the footstep sound effect:
var collisionSoundEffect : CollisionSoundEffect =
other.GetComponent(CollisionSoundEffect);
if (collisionSoundEffect) {
audio.clip = collisionSoundEffect.audioClip;
audio.volume = collisionSoundEffect.volumeModifier * baseFootAudioVolume;
audio.pitch = Random.Range(1.0 - soundEffectPitchRandomness, 1.0 +
soundEffectPitchRandomness);
audio.Play();
}
}
This code looks for a footstep sample in the object we’ve collided with. If it finds one,
it grabs it, copies it into the FootEffect GameObject’s own AudioSource component,
adds a bit of random variation to its pitch, then plays it.
The only other function in this script is Reset(), which simply ensures two key properties
are set to the correct default values. This function is called automatically by
25
Unity when the script is first added to a GameObject, and it can also be called manually
by clicking on the cogwheel
icon to the right of the script component’s name in
the Inspector.
function Reset() {
rigidbody.isKinematic = true;
collider.isTrigger = true;
}
@script RequireComponent(AudioSource, SphereCollider, Rigidbody)
The very last line in the code is a Unity directive which ensures the three components
listed are present in our GameObject. This saves having to remember to add them
manually.
The Camera
It’s now time to look at operating the Camera. We need it to follow our player around
the level.
Save the scene you have built so far and reopen the Scene named 2D Platformer
that came premade
with this tutorial.
Play the Scene for a moment and observe the camera movement.
• You should see that not only does the camera follow the character, but the character's
position shifts as he walks further in a single direction. This subtle movement allows
the player to more easily view what's ahead. This is a technique which can be seen in
games as old as Williams’ classic arcade game, “Defender”.
• In addition to this basic movement, we also added a "Springiness" property to our
camera’s script: When the character jumps, it is preferable not to have the camera follow
the entire jumping motion because it makes for some jerky camera movement. To
solve this problem, we provide a setting that allows the camera to lag a little so it
doesn't follow every single motion.
• The third and final point to note is the camera’s behavior at the boundaries of the
world. Notice how the camera does not move past the boundaries.
Having a wellplaced
camera is almost always difficult no matter what type of game
you are making, and therefore can often get complicated. The camera motion we
provide in this tutorial may not be perfect in every way, but it is a good place to start.
26
Object Profile: Main Camera
This provides the player’s view of our Scene and is an important part of our game.
Components
• Camera
This is the core component for a Unity camera. It is a complex component which relies
on the following Components, (which Unity will normally add automatically):
‣ GUI Layer
This allows 2D GUIs to be rendered.
‣ Flare Layer
This allows lens flare effects to be rendered. These are beyond the scope of this tutorial.
‣ Audio Listener
This is basically a microphone attached to the camera. Traditionally, the microphone
is attached to the camera because it allows for more realistic stereo sound as it represents
the player’s point of view. Without this component, we would not hear any
audio while playing our game.
Script: CameraScrolling
This is the script that makes the camera move how we want. There isn't much to adjust
here except for:
• Distance
This is the distance in the zdirection
that the camera is from the target object.
• Springiness
As we stated earlier, when the character jumps it is preferable not to have the camera
follow the entire jumping motion because it makes for jerky motion. This setting defines
how responsive our camera will be to the target's motion.
Script: CameraFocus
This script allows us to easily switch between different targets for the camera. In our
case, the targets will be Lerpz and the Spaceship.
NOTE This script also takes advantage of the new GUI features in Unity 2.0. In the
premade
scene we have set up for you, this script is what allows you to toggle
between the Lerpz and the Spaceship.
Let’s take a look at the adjustable settings:
• Targets
You can set as many targets as you like. Our preassembled
scene has two. You need
to drag a Transform object from the Hierarchy into the slot.
27
• Target Button Names
This should have as many names as there are targets. These are the names that appear
on the buttons of the GUI display panel.
Further Analysis
We will take a closer look at the camera scripts in the next section of this tutorial.
Continuing our Level
Now that we have an idea what components and scripts we need, it’s time to get the
camera working in our new Scene...
Reopen your scene, if it’s not already open.
Experiment with the Springiness and Distance settings in the CameraScrolling
script. Set them according to your preference.
There is another camerarelated
script which is not applied to the camera itself. We
need to examine this too. It is the CameraTargetAttributes script.
This script is applied to the Character, and later will be applied to the Spaceship.
Script Profile: CameraTargetAttributes
Provides a few additional camera movement properties that aren't applied onto the
camera itself.
Applied To:
Character (Lerpz) and Spaceship
Key Properties
Height Offset
When at 0, the target will be sitting vertically in the center of the screen. If it is set to
a positive number, that means the camera will shift upwards, resulting in a vertically
offcenter
target.
Distance Modifier
The distance of the camera from the target is defined in the CameraScrolling script,
but this setting adds on to that value. In the preassembled
scene the rocket has a
higher distance modifier, so the camera pulls back a little when you choose to control
it.
Velocity Look Ahead
This defines how quickly the camera shifts to "look ahead" when a character is moving.
28
Max Look Ahead
This distance is where the "looking ahead" will stop so the character doesn't leave the
screen. X represents the horizontal distance, Y represents the vertical distance.
Before you move on, play around with the Lerpz's Camera Target Attributes settings
to understand what this script does.
Orthographic Projection
Even though we are working with 2D mechanics, the graphics are still 3D and everything
still has a bit of perspective to it. For you traditionalists out there, just follow
these steps so it's strictly sideview
orthographic with no perspective:
In the Hierarchy, select your Main Camera, and check the box in the Inspector
that says "Is orthographic."
In the Game View you should see a strict orthographic view of your level without perspective.
But there's a problem now, the Skybox has disappeared because it doesn't
work for orthographic views. No need to worry, a few quick adjustments and we're
back in business!
Adjust a setting of the Main Camera in the Inspector. By default, the setting
Clear Flags is set to Skybox but we want it to be set to Depth Only.
Now we need to add a new camera to render the backdrop.
Go to GameObject>
Create Other>
Camera.
This new camera will be set to only render the Skybox and nothing else.
Change the Depth setting to "2",
which sets it to render before the Main Camera
and therefore will appear in the background.
Now the Culling Mask setting needs to be changed to Nothing, otherwise your
level may be rendered more than once.
You can also adjust the Field of View so that you can see as much or as little of
the skybox as you desire.
Now you have a sidescroller
that has a more traditional feel without perspective!
Handling Rigidbodies
Rigidbodies are the gateway for applying physics to your objects. (If you are unfamiliar
with the concept of a Rigidbody, please view the documentation.)
Our job is to tell the Rigidbodies how to behave in this restrictive 2D plane of motion.
The platforms will never move so the Rigidbody component is not necessary, but the
29
rocket ship and the crates need to move and physically interact with their surroundings.
This section explains how to restrict motion of these Rigidbodies.
If you were to examine both the crate and the rocket in the Inspector View of our preassembled
scene, you would notice two major things that are specific to our 2D game:
• They are both located at 0 along the Zaxis.
This is important because every object
needs to be at the same place along the Zaxis.
• They also have a component called "Configurable Joint." This is a new component in
Unity 2.0 which offers countless possibilities, but for our purposes it is used for restricting
motion.
Notice that ZMotion is locked, which disallows motion in the Zaxis.
Angular XMotion
and Angular YMotion are also locked, preventing any forbidden rotations conforming
with what we decided in the previous chapter. The Configure In World Space checkbox
is also selected. All other settings are left at their default values.
Lets take a closer look at the crate. (The Spaceship has additional components added,
and we will look at that later.)
Object Profile: Crate
In the Project Pane you can find this prefab inside of the directory Level Prefabs. The
crate is not meant to be stationary, but rather interact with the character and the
world around it.
Components
• Box Collider
Without the Box Collider, the object would not be able to physically interact with its
environment. All of the settings here are the default settings.
• Rigidbody
This also allows the crate to physically interact with its environment. The settings here
are also the default values, but you can adjust them to make it more massive, to ignore
gravity, or to be immovable.
• Configurable Joint
This is the component that restricts our movement to our 2D plane. All settings are
default except for the following four:
‣ ZMotion: Locked
‣ Angular XMotion: Locked
30
‣ Angular YMotion: Locked
‣ Configure in World Space: Checked
• Pipeline, Mesh Filter, and Material
These assign the proper mesh and texture so it renders in the scene.
Script: CollisionSoundEffect
This script assigns a sound for when an object collides with it. The colliding object
must activate the sound through scripting.
The humble crate. So versatile! So easy to model! Where would the games industry be without them?
Exercise
Add as many crates to your scene as you want. You can orient them however
you want as long as they're located at zero along the zaxis.
After you have added crates, step it up by creating your own Rigidbody to be
loaded in the scene.
Try creating a sphere that the character can roll when it is pushed. Apply the
same components and settings to the sphere, but make sure you add a Sphere
Collider instead of a Box Collider.
Don't forget to save your scene!
31
Moving Platforms
A common ingredient in a sidescrolling
2D game is a moving platform. To create a
moving platform we’re going to position two waypoints in the Scene that the moving
platform will oscillate between.
Drop the Moving Platform Prefab into your scene.
Drop a PlatformWayPoint Prefab into your scene and position it where you
want the Moving Platform to start from.
Duplicate the PlatformWayPoint and position it where you want the Moving
Platform to move to.
In the Moving Platform’s Inspector there is a script named Platform Mover with
two slots, Target A and Target B. Drop your two PlatformWayPoint GameObjects
from the Hierarchy into their respective slots in the Inspector.
There is also a setting for Speed which controls how fast the Moving Platform
will move between the two PlatformWayPoints.
Now if you hit play, the platform should be moving how you'd expect. If it isn't behaving
correctly, adjust your two PlatformWayPoints and the Speed variable until you
achieve the desired result.
TIP You can add as many moving platforms as you'd like. Each moving platform
should have its own set of two PlatformWayPoints to move between.
32
Object Profile: Moving Platform
Description: The moving platform that the character can stand on. The moving platform
in the preassembled
2D Tutorial scene moves vertically, but they can be made to
move whichever direction you desire.
Components
• Box Collider
Without the Box Collider, the character and other objects would fall right through it!
• Rigidbody
This also allows the crate to physically interact with the character and other objects. A
few settings deviate from the default. "Use Gravity" setting is off. The "Is Kinematic"
setting is on. The "Is Kinematic" setting prevents the character or other Rigidbodies
from moving the platform somewhere besides its predefined path.
• Configurable Joint
Like the Rigidbodies described in the previous section, this component restricts our
movement. Everything is the same except now ALL rotation is forbidden:
‣ ZMotion: Locked
‣ Angular XMotion: Locked
‣ Angular YMotion: Locked
‣ Angular ZMotion: Locked
‣ Configure in World Space: Checked
33
• Pipeline, Mesh Filter, and Material
These assign the proper mesh and texture so it renders in the scene.
Script: MovingPlatformEffects
This script is used to activate the particle effects on the bottom of the platform. The
Horizontal Speed to Enable Emitters property defines how fast the platform needs to
move horizontally for the jets to fire. It automatically fires for any vertical movement.
We’ll take a more indepth
look at this script later.
The Spaceship
By now you should have almost everything set up. Lerpz, the character, should be
moving around and navigating over crates and movable platforms. The last thing you
have to set up is the Spaceship. Adding a spaceship in this tutorial will show you how
to add forces to a Rigidbody and make it move.
There are only two things you need to do to get the Spaceship fully functional:
First drag the Spaceship Prefab into the Scene.
Position it where you want in your level.
Now we need to adjust a few settings in the Main Camera so that the camera will
switch between the Spaceship and Lerpz. It's time to revisit the CameraFocus script:
Change the number of Targets to 2 with Element 0 as Character (Lerpz) and
Element 1 as Spaceship. This easily achieved by dragging the respective
GameObjects onto the “Element” slots.
You also need to change the size of Target Button Names to 2, with Elements 0
and 1 named Player and Spaceship respectively. You can see the final settings in
the following screenshot.
Now you're good to go!
34
The updated Camera Focus script settings.
You should by now have a complete and working level! If anything isn't working
properly, read back and see if you missed anything. Also remember that you can always
open the scene 2D Tutorial and use that as a reference.
Don't forget to save!
Object Profile: Spaceship
The Spaceship prefab can be found in the director Level Prefabs. It's the Spaceship you
fly around the level with.
Components
• Mesh Collider
Allows the object to physically interact with its surroundings. It is important that Convex
is checked. A convex Mesh Collider is able to move in realtime,
otherwise it is too
computationally expensive to run. To see the definition of a Convex Mesh, you can
view the documentation
(http://unity3d.com/Documentation/Components/classMeshCollider.
html).
• Rigidbody
This also allows the Spaceship to physically interact with its environment. The settings
used are the default settings when you apply a Rigidbody to an object.
• Configurable Joint
The standard settings that we apply to other Rigidbodies in the scene as seen on our
crate:
‣ ZMotion: Locked
35
‣ Angular XMotion: Locked
‣ Angular YMotion: Locked
‣ Configure in World Space: Checked
• Pipeline, Mesh Filter, Mesh Renderer, and Material: These assign the proper mesh and
texture so it renders in the scene.
Script: Spaceship
So far the Spaceship is not much different from the crate, but this script is what sets it
apart from an inanimate physics object.
The Spaceship script defines how it moves with the input from the keyboard. The adjustable
settings on the script are:
• Forward Direction
• Positional Movement
• Rotational Movement.
For both Positional and Rotational Movement, you'll see that there is a max speed
and, by default, if that speed is exceeded the drag drastically increases, making it
much more difficult to accelerate.
The setting Can Control is toggled with the camera script CameraFocus, so you need
not worry about that setting.
Well Done!
Congratulations! You are finished with building your 2D level. This was no easy task throughout
the tutorial so far you have been introduced to a handful of fundamental
concepts . . . and some more advanced concepts. Here's what you should have accomplished
so far:
• Learned how to restrict movement to a 2D plane;
• Built your level with tileable platforms;
• Set your level boundaries;
• Been introduced to Gizmos;
• Explored the fundamentals of setting up a Character;
• Explored the complexities of setting up your camera;
36
• Seen how to make a strict orthographic camera view;
• Learned how to place and make Rigidbodies;
• Used waypoint system to create moving platforms;
• Set up the Spaceship.
Take a moment for a deep breath and enjoy playing your level. Then, if you're ambitious
you can dive into the next chapter.
37
Delving Deeper: Scripting Examples
Studying the Scripts
There are a lot of scripts within this project, and we will only cover a few of the more
important ones. For the ones we do not cover in the tutorial text, you will see that the
scripts are thoroughly commented so you can walk through them by yourself. These
scripts cover both basic and advanced concepts, so whether you're new to Unity or a
seasoned user you will benefit from reading them.
Moving Platform Particle Effects
If you watch the moving platform, you'll notice that the particle effect only occurs
when it is moving upwards. This effect was accomplished with the script MovingPlatformEffects.
In a nutshell, this script compares the previous position with the current position and
if it's moving upwards the particle emitters turn on. Note the usage of the LateUpdate()
function instead of Update() this
is to stop the particle emitter from reacting
one frame late.
var horizontalSpeedToEnableEmitters = 1.0;
private var areEmittersOn : boolean;
38
Now we’ve learned how
the project is organized
and how to use the tools
provided, it’s time to peer
under the hood and see
how these tools work.
private var movingPlatform : MovingPlatform;
private var oldPosition : Vector3;
private var currentVelocity : Vector3;
function Start() {
oldPosition = transform.position;
}
function Update() {
wereEmittersOn = areEmittersOn;
areEmittersOn = (currentVelocity.y > 0) || (Mathf.Abs(currentVelocity.x) >
horizontalSpeedToEnableEmitters);
if (wereEmittersOn != areEmittersOn) {
for (var emitter in GetComponentsInChildren(ParticleEmitter)) {
areEmittersOn
emitter.emit = areEmittersOn;
}
}
}
function LateUpdate () {
currentVelocity = transform.position - oldPosition;
oldPosition = transform.position;
}
@script AddComponentMenu("2D Platformer/Moving Platform/Moving Platform Effects")
39
The Camera Scrolling Script
Now lets examine how we get the camera to follow the character. To accomplish this
we use scripting. A simple yet functional camera script could be applied to the main
camera, read the character's X and Y coordinates, and use those values for its own position
while keeping a certain distance away in the Zaxis.
This works perfectly well,
but if you closely examine popular sidescrolling
games you'll notice that it's never
quite that simple: there are a handful of subtle touches to be made in order to get
effective camera scrolling.
All of this movement is defined in CameraScrolling found in Scripts>
2D>
Camera.
Open the script and examine it. Use the comments we supplied to understand how it
works. Here we will briefly describe what each function does:
• SetTarget()
Look at the top of the script and you'll notice a private variable called target. The
SetTarget() function is used by other scripts to change the private variable target.
More specifically, the CameraFocus script uses this function when you click on the buttons
at the top of the screen to choose whether to control Lerpz or his spaceship.
Why not allow setting of the variable directly? Simple: this way we can ensure that the
variable is always set by calling our SetTarget() functions, making it easier to
check that the value we’re setting it to is a valid one for our purposes.
Note also that we define the SetTarget() function more than once. Each definition
accepts a different number of arguments (otherwise Unity will complain). We can use
these multiple definitions as an easy way to default the second argument to FALSE
and also to make our scripts easier to follow. (This programming technique is most
commonly referred to as “Overloading”.)
• GetTarget()
This is a simple accessor function, (sometimes called a "getter"). It is a publicly callable
function that returns a private variable. Notice how target, defined at the top of the
script, is marked "private"? We can not access it directly from another script, but another
script can access this function.
Functions like this enforce a concept called “encapsulation”. In Unity, this means our
script is completely selfcontained.
Other scripts don’t need to know how it works internally
and this helps us reduce bugs, as well as making our scripts easier to reuse
in
other projects.
• LateUpdate()
We're using LateUpdate() instead of Update() to ensure that the camera isn't
40
lagging a frame behind of the motion. This function uses the function GetGoalPosition()
to interpolate between the current camera position and the goal position.
• GetGoalPosition()
This function calculates where the camera should be when the next frame is drawn.
(This part of our script seems fairly longwinded,
but much of it deals with how the
camera behaves at the boundaries of the level, which involves performing similar, but
not identical, tests for each edge.)
Streamline Your Workflow
An important concept to keep in mind for any project is how to optimize your workflow.
One way to optimize your workflow is included within this tutorial. By harnessing the
flexibility of Unity, you can create scripts that automate certain procedures for you.
More specifically, in this tutorial you'll notice a menu at the top of the screen titled
"2D" that contains two items that automate the process we just described.
Give one of these menu items a try by dragging a crate prefab into the Scene View.
Select the crate in the Scene View, go to 2D>
Move Onto 2D Plane. If it wasn't
already, you'll notice that the crate's Zposition
has changed to zero.
The other menu item is not necessary for the crate since that prefab already has the
Rigidbody (and other required components) attached.
Creating custom menu commands can be surprisingly simple! Below we explain the
script used to create these menu items. The script below, titled TwoDHelper can be
found in the Project Pane within the Editor folder.
NOTE Scripts that add custom menu items must be located in the Editor folder.
First up, we have the 2D menu’s Move Onto 2D Plane function.
This menu item has two functions: MoveOnto2DPlane() itself, which performs the
function we want; and ValidateMoveOnto2DPlane(), which tells the Unity Editor
when to enable the menu item. (Not all menu commands will need the latter function.)
@MenuItem ("2D/Move Onto 2D Plane ^2")
static function MoveOnto2DPlane () {
for (var transform in Selection.transforms) {
transform.position.z = 0;
}
41
}
@MenuItem ("2D/Move Onto 2D Plane ^2", true)
static function ValidateMoveOnto2DPlane () {
return (Selection.activeTransform != null);
}
The validation function merely checks that we have a GameObject selected. (We actually
check if the currently selected object has a Transform as all GameObjects have one
of these Components.)
The second menu item performs the same moveto2Dplane
action by calling
MoveOnto2DPlane() first, then goes ahead and adds the RigidBody and Configurable
Joint Components we need for a GameObject to work in our 2D game. It even
ensures the Configurable Joint Component’s zMotion, angularXMotion and angularYMotion
properties are set to “Locked” for us.
NOTE Both our menu commands will loop through whatever GameObject we’ve selected
and apply the same instructions on any child GameObjects it contains.
@MenuItem ("2D/Make Selection 2D Rigidbody")
static function MakeSelection2DRigidbody () {
MoveOnto2DPlane();
for (var transform in Selection.transforms) {
var Rigidbody : Rigidbody = transform.GetComponent(Rigidbody);
if (!Rigidbody)
transform.gameObject.AddComponent(Rigidbody);
var configurableJoint : ConfigurableJoint =
transform.GetComponent(ConfigurableJoint);
if (!configurableJoint)
configurableJoint =
transform.gameObject.AddComponent(ConfigurableJoint);
configurableJoint.xMotion = ConfigurableJointMotion.Free;
configurableJoint.yMotion = ConfigurableJointMotion.Free;
configurableJoint.zMotion = ConfigurableJointMotion.Locked;
configurableJoint.angularXMotion = ConfigurableJointMotion.Locked;
configurableJoint.angularYMotion = ConfigurableJointMotion.Locked;
configurableJoint.angularZMotion = ConfigurableJointMotion.Free;
42
}
}
@MenuItem ("2D/Make Selection 2D Rigidbody", true)
static function ValidateMakeSelection2DRigidbody () {
return (Selection.activeTransform != null);
}
Spaceship Script Part 1: Defining Helper Classes
The next script we will be examining is called Spaceship and can be found in the Project
Pane in Scripts>
2D>
Spaceship. For the sake of saving space the entire script will
not be listed in this text, but can be examined on your own by using the comments we
provide throughout.
While the spaceship is selected in the hierarchy, look in the Inspector at the
Spaceship component.
Notice the Positional Movement settings and Rotational Movement settings are identical.
They both have Max Speed, Negative Acceleration, Drag While Coasting, etc.
Since these settings are identical, this is a perfect opportunity to create a helper class.
If used correctly, a helper class can be used to create much cleaner and reusable code.
You will see later where and how we use this class, but for now we will just define it.
(Another advantage to defining a helper class such as this is its properties will be
grouped together by the Inspector, making for a much cleaner interface.)
...
class MovementSettings {
var maxSpeed : float;
var positiveAcceleration : float;
var negativeAcceleration : float;
var dragWhileCoasting : float;
var dragWhileBeyondMaxSpeed : float;
var dragWhileAcceleratingNormally : float;
function ComputeDrag(input : float, velocity : Vector3) {
var drag = 0.0;
floats)
if (Mathf.Abs(input) > 0.01) {
drag
43
if (velocity.magnitude > maxSpeed)
drag = dragWhileBeyondMaxSpeed;
else
drag = dragWhileAcceleratingNormally;
}
else
drag = dragWhileCoasting;
return drag;
}
}
The function ComputeDrag() defined in the MovementSettings class above will be
used later in the script. Computing the drag is the same for both angular and positional
movement, so putting it in the helper class means we don't have to write the
same code twice when determining which drag to use.
Next we will define one more helper class to use later for adding particle effects to
the spaceship. This one is a bit shorter and sweeter.
@script System.Serializable
class SpecialEffects {
var positiveThrustEffect : GameObject;
var negativeThrustEffect : GameObject;
var positiveTurnEffect : GameObject;
var negativeTurnEffect : GameObject;
var collisionVolume = 0.01;
}
Spaceship Script Part 2: Controlling the Spaceship
The next chunk of code shown below is simply defining our variables that will show
up in the Inspector.
We're putting our MovementSettings helper class into good use. We define both positionalSettings
and rotationalSettings as a MovementSettings class type.
var forwardDirection : Vector3 = Vector3(0.0, 1.0, 0.0);
44
var positionalMovement : MovementSettings;
var rotationalMovement : MovementSettings;
var specialEffects : SpecialEffects;
Now we finally get to the heart of the script. Above we have defined everything that
we need, and now we put those items to use.
function FixedUpdate() {
responsiveness of the controls.
thrust = Input.GetAxisRaw("Vertical");
turn = Input.GetAxisRaw("Horizontal");
for the positional movement.
the top of this script.
Rigidbody.drag = positionalMovement.ComputeDrag(thrust, Rigidbody.velocity);
Rigidbody.angularDrag = rotationalMovement.ComputeDrag(turn,
Rigidbody.angularVelocity);
then modifies thrust/turn with //the given accelerations.
"if...else" statement pair. See
thrust *= (thrust > 0.0) ? positionalMovement.positiveAcceleration :
positionalMovement.negativeAcceleration;
turn *= (turn > 0.0) ? rotationalMovement.positiveAcceleration :
rotationalMovement.negativeAcceleration;
move it.
need to change your Time.fixedTime
Rigidbody.AddRelativeTorque(Vector3(0.0, 0.0, -1.0) * turn * Time.deltaTime,
ForceMode.VelocityChange);
Rigidbody.AddRelativeForce(forwardDirection * thrust * Time.deltaTime,
ForceMode.VelocityChange);
45
}
choose Reset on the
Next, we define some default values that appear if you choose Reset in the Inspector.
choose Reset on the
function Reset() {
positionalMovement.maxSpeed = 3.0;
positionalMovement.dragWhileCoasting = 3.0;
positionalMovement.dragWhileBeyondMaxSpeed = 4.0;
positionalMovement.dragWhileAcceleratingNormally = 0.01;
positionalMovement.positiveAcceleration = 50.0;
positionalMovement.negativeAcceleration = 0.0;
rotationalMovement.maxSpeed = 2.0;
rotationalMovement.dragWhileCoasting = 32.0;
rotationalMovement.dragWhileBeyondMaxSpeed = 16.0;
rotationalMovement.dragWhileAcceleratingNormally = 0.1;
rotationalMovement.positiveAcceleration = 50.0;
rotationalMovement.negativeAcceleration = 50.0;
}
Last, we tell Unity which components are needed when this script is attached. This is
actually found at the very bottom of the script. It is not required to be at the bottom,
but for the sake of consistency you will notice that every time RequireComponent()
is used in our scripts it is at the bottom.
AudioSource component.
46
@script RequireComponent(Rigidbody, AudioSource)
Spaceship Script Part 3: Special Effects
With the script above, we have a fully functional spaceship that is controlled by the
player. However, to give it a little more mojo we want to add some special effects.
The remaining sections of the Spaceship script deal with the special effects.
Briefly, all the particle effects are taken care of within the Update() function. It ends
up being partitioned nicely since all of the physics and controls are taken care of
within the FixedUpdate() function.
The sound effects are executed with the OnCollisionEnter() function.
Read through the script to understand how it works, using the comments we included
to assist you.
NOTE The spaceship currently has only one particle effect that occurs when forward
thrust is occurring, but the script allows for particle effects in all directions.
This is a good example of reusable code for various different purposes.
As an exercise, we suggest adding more particle effects for thrust in the other directions.
Finished!
If you have reached the end of this section you should be proud. You didn't really add
much to your level in this section, but you did expand your knowledge base. You can
use some of the tools and concepts you learned here and apply them to countless
other projects. Even if you didn't completely grasp all of the scripts, that's okay just
store this project away and keep these scripts in mind to use as a resource later on.
Now, prop your feet on the desk and enjoy a nice tall glass of beer lemonade you've
earned it.
(Disclaimer: Unity Technologies and Graveck Interactive do not condone drinking on
the job or any other inappropriate or illegal alcoholic consumption.)
47
What's Next?
Your Turn
In this tutorial we have looked into the basics of building 2D games using 3D tools.
Now it’s time to take off those little stabilizing wheels from the bicycle of wisdom and
ride off on our own! Here are some suggestions...
Improve the game’s UI
At the moment, the only way to switch between Lerpz and the Spaceship is by clicking
on a button with the mouse. This breaks the continuity of the game world by requiring
the use of a completely different input device. There are two possible solutions to
this:
Use the keyboard instead.
Replace the GUI with a keyboard command to toggle between Lerpz and the
Spaceship. (Adding and changing controls in Unity is covered in the User Guide.)
Allow Lerpz to enter the Spaceship.
Have the control automatically switch to the Spaceship when Lerpz touches it.
The tricky part is to make it look as if Lerpz has stepped inside you’ll
need to
hide the Character (Lerpz) model while the Spaceship is being controlled.
You’ll also need to add a way to exit the Spaceship perhaps
by having Lerpz
reappear when it lands, or by adding a new keyboard command.
48
Here are a few challenges
we give you to make this
2D platform game more
complete.
Add some bling
What sidescrolling
platformer would be complete without some sort of coin, ring, or
other sort of bling.
Here's a starting point if you need it:
Create an object (a cylinder perhaps) that has Rigidbody and Collider components.
Don't forget to apply the usual 2D restrictions.
One method of completing this task would be to have the bling be a trigger. When
the character hits the trigger, a message is sent from the character to the object that
in turn triggers forces/torque to make it spin and fly off the screen.
If you're really ambitious you could have it trigger sound and particle effects.
Add more pizzazz to the spaceship
Currently, the space ship has one particle effect for the forward thrust. Try adding
particle effects for turning the spaceship. This will be good practice working with particle
effects. Don't just reuse the same flame effect experiment
and change it up a
little! Additionally, you could have the spaceship thrust backwards. This entire task
requires no additional scripting!
Have the Death Zone respawn
the Spaceship
Look through the scripts to explore how the character is respawned
and apply the
same method to the Spaceship through scripting.
Turn it into a game
Lerpz doesn’t really have a goal at the moment. This tutorial was designed to educate
and hasn’t dipped into game design issues. Consider the tutorial as a starting point
and try making a complete game with it! Add some enemies to fight, puzzles to to
solve and all the other trappings of a platformer.
49