When last we left Ticker Taker, our slightly demented hospital-themed keep-up game, we had two hands bouncing a heart on a dinner tray. The game mechanic was pretty functional, but we hadn't fully delivered on the skin. If Ticker Taker is about a nurse rushing a heart to the transplant ward, then where is the hospital?
In this final chapter we'll:
Use the dual-camera technique from Shoot the Moon to render a fully-3D environment
Set up a movable lighting rig for our Scene
Dive into Unity's animation tools to animate Game Objects
Publish a Unity game so that we can unleash our masterpieces on an unsuspecting public
Once the project is open, find the Game Scene in the Project panel and double-click to open it (if it doesn't open by default). You should see the Scene just as we left it: heart, hands, and tray.
I took the time to organize the different assets into folders to tidy up the project. Recall that as your projects become more complex, neatness saves sanity.
We're going to set up one camera to bounce up and down, as if the character is running, and send it flying through the hallway. Then we'll set that view as the background for our Main Camera, which is aimed at the heart-and-tray action. By using Depth as our Clear Flags setting on the foreground camera, the background camera will show through the empty space to make it appear as though the player is running through the hallway.
Find the hallway model in the Project panel. It's the one with the blue cubic "model" icon next to it not to be confused with the model texture, which uses a little image thumbnail as its icon. (I placed my models in the folder called
Models, and dropped my textures into a
Textures folder to keep them sorted.)
Drag the hallway model into the Scene.
Position: X:0, Y:2, Z:-25
Rotation: X:0, Y:0, Z:180
These settings place the hallway behind the Main Camera in our Scene so that it's out of the way while we work with it. In the Hierarchy panel, select the hallway Game Object and press F to frame the selected object.
In the Inspector panel, add a new layer called hallway, as we did when we created the starfield layer in our Shoot the Moon project. Be sure that you're adding a new layer, not a new tag.
In the Hierarchy panel, select the hallway. Choose the new hallway layer in the Layer drop-down. Unity will pop up a dialog asking you whether you want to put the hallway's child objects in the hallway layer as well. Answer Yes, change children.
In the menu, select GameObject | Create Other | Camera.
Rename the new camera as hallwayCam.
Change the Transform settings of hallwayCam to:
Position: X:6.5, Y:1.2, Z: -31.5
The hallwayCam jumps to one corner of the hallway model.
Select the hallwayCam in the Hierarchy panel.
In the Inspector panel, adjust the following settings:
Clear Flags: Solid Color
Culling Mask: nothing (This deselects everything in the culling mask list.)
Culling Mask: hallway (This selects only the hallway layer, which contains our hallway model.)
Flare Layer: unchecked/removed
Audio Listener: unchecked/removed
In the Hierarchy panel, select the Main Camera.
In the Inspector panel, adjust the following settings:
Clear Flags: Depth only
Culling Mask uncheck hallway (it now says Mixed...)
This bland gray hallway model looks less like a hospital and more like the white light patients see when they quit the mortal coil. Luckily, there's a quick fix: the Project panel contains a texture that we'll apply to the model to make it look more you know hospitable.
In the Hierarchy panel, click on the gray arrow next to the hallway to expand its list of children.
The hallway contains one child, also called Hallway, which contains the Mesh Renderer and Mesh Filter components. Select the Hallway child.
This hospital texture is great and all, but our level looks like something straight out of a survival horror game. Every hospital that I've ever visited has been bright and shiny. Let's add some lights to the level to perk it up some.
Pan and zoom the Scene view to center the hallway model.
In the menu, select GameObject | Create Other | Point Light.
Create a new prefab and call it hallwayLight.
Drag the Point Light into the hallwayLight Prefab.
Drag an instance of the hallwayLight Prefab from the Project panel into your Scene. Position it at the top-right corner of the hallway around x: 6.3 y:1 z:-19.7.
Note: We could have kept the Point Light in there, as it's connected to the hallwayLight Prefab, but I think it's easier to work with the project when Prefab instances are named consistently.
In the Hierarchy panel, click-and-drag the hallwayLight instance onto the LightingRig Game Object. This makes the light a child of the rig, and we see that familiar gray arrow appear indicating a parent/child relationship.
Select and then duplicate the hallwayLight instance by pressing Ctrl + D (Command + D on a Mac). Notice that the second light is also a child of the LightingRig Game Object.
Duplicate a third light, and move it to the top-left corner of the level.
Hold down the Shift key on your keyboard and click on the other two lights, until all three lights are selected at once. (It may be easier to shift-select the three lights in the Hierarchy panel instead of the Scene view.)
Duplicate the trio of lights, and move them down across the middle of the level. You may need to zoom out slightly to see the transformed gizmo handles.
Click to select the light in the middle of the level and delete it. Now there's a light in each corner, and a light in the middle of each hallway section.
Unity 3D supports "expensive" pixel lighting and less "expensive" vertex lighting. Pixel lighting is more taxing on the player's computer, but it's more believable and it can pull off fancier tricks like cookies (think of the "bat symbol" from the Batman comics) and normal-mapping, which creates the illusion of detail on a flat polygon. In trying to preserve performance, Unity only lets us have two active pixel lights and drops the other lights down to vertex quality, which interpolates (makes a calculated guess) at the light levels between the light source and an object.
In order for our lighting rig to light the hallway well, we need to tell Unity that it can use all of our lights as pixel lights. This is sort of a lazy solution, but we can get away with it because our geometry is so simple. In more complex games, you may need to employ real ingenuity to present your scene in the best possible "light" with minimal performance trade-off.
Follow these steps to increase the number of pixel lights Unity will allow:
In the menus, click Edit | Project Settings | Quality. Unity allows us to create different quality profiles, and to apply those profiles to different scenarios: playing a game standalone, using the web player, deploying to a mobile, and viewing a game in the editor. Note that all of these scenarios default to using the "Good" profile.
Once you make this change, you should see the light levels in your scene punch up. Now Unity is rendering proper lighting effects for every pixel on the screen based on all eight lights, rather than calculating only two lights and fudging the others.
The light! It bliiiiiiiinds! Luckily, these eight lights are all instances of the same Prefab, so by adjusting one of them, we'll affect the rest.
In the Inspector panel, change the intensity to 0.5 and the range to 20.
When you rotate your Scene view, you should see all eight lights nestled within the hallway model. If they ended up far above or below the level, just move the LightingRig Game Object around to move all eight lights as a single unit.
We want to depict the player running through these hallways. There are at least two ways we can handle the HallwayCam's animation. We can use a Script to control the camera motion, or we can use Unity's built-in animation tools to record some camera motion that we'll play back during gameplay. We've already done a bunch of scripting, so let's see what the Unity IDE can do to help us pull off our running-through-the-hallway effect without writing any code.
We're going to build a camera rig, where the camera is a child of a Game Object that bounces up and down, and that Game Object is a child of another Game Object that runs through the hallways.
Order of operations
Because of the way Unity's built-in animations work, it's super important to set up your objects' parent-child relationships before you animate. The values we set in our animation clips become relative to an object's parent. In short, that means "bad news" if you animate first before setting up your rig. Existing animations can swing wildly out of position. Because redoing work is for chumps, let's get it right the first time.
Set its Transform using these values:
Position: X: 6.5, Y:1.2, Z:-31.5
These are the same values as for the hallwayCam.
Duplicate the bouncer Game Object and call it runner.
In the Hierarchy panel, make the hallwayCam a child of the bouncer by clicking and dragging hallwayCam onto bouncer.
In the Hierarchy panel, click to select the bouncer Game Object.
In the menu, select Window | Animation to bring up the Animation window. If you so choose, you can dock it within the interface like the Hierarchy and Project panels. I prefer not to because I like having a lot of space for this window. I resize the window so that it covers most of the right half of my screen. You can drag the middle line that splits the Animation window (dividing the dark and light parts of the window) to give more or less real estate to the key view (dark side).
Click the round reddish-pink Record button near the top-left of the window.
Unity asks you to name your new Animation clip. Save it as animBounce.
When you save your animation clip, two things happen: the clip becomes a tangible, reusable asset in your Project panel, and the Record button and Play, Pause, and Step buttons all light up red to notify you that you're in animation mode.
Why make such a big, noticeable deal out of it? Because whenever you move your recorded GameObject around, Unity is going to remember its position, rotation, and scale in a keyframe. Keyframe is a term borrowed from classical animation. Animation software packages store the position, rotation, and scale values of objects in keyframes, and use a process called interpolation to figure out how to animate an object between those keys. In classical animation, this is called in-betweening.
If you create a keyframe for a Game Object on frame 1 and another on frame 10 where the Game Object is moved across the screen, Unity will interpolate between those two keyframes, filling in the blanks to make the Game Object move from one side of the screen to the other.
Click on the X cone in the Scene view's axis gizmo to view the level from the side.
In the Animation view, enter an initial value of -0.5 for the bouncer's Position.y value. A little, diamond-shaped keyframe symbol appears on frame 1 at the top of the Animation view. This means that Unity is remembering the position, rotation, and scale of the Game Object on that frame.
Click-and-drag the vertical red line (not the keyframe diamond) to frame 10, or enter the number 10 into the frame field at the top of the Animation window (next to the playback controls). It's very important not to mistake frame 10 with the 10:00 second mark!
On frame 10, punch in a Position.y value of -0.1. A second keyframe is created for us on frame 10, storing the new values.
Go to frame 20.
Enter the initial Position.y value of -0.5 to bring the bouncer back to the top of its bounce. A third diamond keyframe icon appears.
The animation arc between keyframes for the bouncer's y position spans into infinity to indicate that the animation loops. (You may have to pan and zoom around the Animation view to see this using the same controls that you use to pan and zoom around your 3D Scene.)
Click on the Record button to stop recording.
Test the game.
Now, Nurse Slipperfoot bounces the heart on the tray while running on the spot! That's great for her personal calisthenics routine, but not so hot for her poor transplant patient.
Note: If it doesn't work, check to make sure that the animBounce animation component is attached to the bouncer Game Object.
When you test your game, you should see the hallway snap to the X and Z position defined in our animBounce animation keyframes. The entire hallway model bounces up and down just like our bounce Game Object did. You can apply the same animation to the heart or the tray. Just as you can apply one script to many different Game Objects, a single animation can go a long way.
Click on the green Y-axis cone to switch into top view. Pan and zoom so that the hallway fills the Scene view, like it did when we were building our lighting rig.
In the Hierarchy panel, select the runner Game Object.
In the Animation window, click on the Record button.
Name the new animation animRun. A new, reusable animation appears in the Project panel.
Punch in the following values on frame 0:
If those values are already punched in when you create the animation, click on one of them and press the Enter key to make sure Unity registers a diamond-shaped keyframe to remember those settings.
Click on the little, gray dash symbol to the right of the Rotation.x value. You'll find a small drop-down menu. Choose Add Curves from that list. We're adding curves to the rotation values because we'll need to modify them later.
Go to frame 120.
Move the runner up along the Z-axis to the top-right corner of the building, or type in -19.4 for its Position.z value. Note: you'll have to press the Enter key on all three x, y and z values to make them "stick" on this keyframe if you decide to key in the values by hand.
Go to frame 240.
Move the runner along the X-axis to the top-left corner of the level, or key in -6.5 for Position.x.
Move to frame 360.
Move the runner down in the Z-axis to -31.5 to the bottom-left corner of the hallway.
Go to frame 480.
Move the runner along the X-axis back to the bottom-right corner where it started. Use these values:
Set this Animation clip to Loop, just like the bounce.
At this point, it looks like Nurse Slipperfoot herself may be in serious need of medical attention. True, we haven't rotated her to look down the hallways, but even so, she flies through the emergency ward like a banshee, busting through walls and generally freaking me out.
That's because like other 3D programs, Unity gives us Bezier control over our keyframe values. A Bezier is a line that you can bend with little handles, which can either work separately or in tandem to create smooth motion. This enables us to ease animations in and out so that they look less robotic (or not, depending on our needs).
You can mess around with each node's Bezier handles by clicking on the dots in the Animation window, selecting a handle style from the right-click menu, and pulling the little gray handles around, provided the keyframes are set to Flat, Broken, or Free Smooth. To correct this animation simply, we're going to apply a boring straight line between all of the key points.
In the Animation window, press Ctrl/Command + A to select all of the nodes in the animation.
Right-click/secondary-click on any one of the nodes.
Select Both Tangents | Linear to flatten the curves between the nodes.
Test your game.
Note: If Nurse Slipperfoot is still phasing through walls, you may need to revisit your keyframes and make sure she's positioned correctly at each corner of the hallway on frames 0 (bottom-right), 120 (top-right), 240 (top-left), 360 (bottom-left), and 480 (bottom-right). If she's not ending up where you think she should be, you may have forgotten to punch Enter to confirm all three position axes x, y and z on all of the frames we just modified.
In the Animation window, go to frame 100. This is 20 frames before our next keyframe.
Click on the little button with the white diamond and plus symbol the "add keyframe" button to tell Unity to remember the Runner's position/rotation/scale on this frame.
Go to frame 120.
Enter a Rotation.y value of -90 to face the camera down the next hallway.
Move the Runner down the second hallway just a bit, maybe to Position.x 6.0, to make the motion slightly less robotic.
Go to frame 220 and add a new keyframe.
On frame 240, rotate the Runner to Rotation.y: -180 to aim it down the third hallway.
Keep repeating these steps through the rest of the animation. Set a keyframe 20 frames before the existing one, and then move to the corner keyframe and set the Y rotation. Use -270 and -360 for the next two Y rotation values.
Select all of the keyframes and set their curves to linear.
Stop recording animation, and test your game.
The runner tears down the hallways, turning the corners and facing the proper direction. Having a hospital background cranks up the credibility and polishes of this game so much! It's like a doctor-prescribed injection of awesomeness.
Anticipating the turns
Are you wondering why we dropped a keyframe 20 frames before turning the corner? If we had simply rotated the Runner at each corner, Unity would have tweened towards that new rotation the entire time the nurse was running down the hallway. We want the rotation to stay constant almost to the end of the hallway, so we set a keyframe as a sort of break point to tell Unity "okay, you can start tweening the rotation right here."
With straight Bezier curves connecting our nodes, our Runner animation tends to look a little artificial or robotic. Now that you've seen the right-click menu to adjust the smoothness of those Beziers, why not spend some time fiddling with the handles to see if you can eke out a more natural motion through the hallway? But first, a warning: adjusting Bezier handles for 3D animation can be very time-consuming! If you get bogged down, or lose heart, just select the nodes and slap "Linear" on them to be done with it. That's the equivalent of blowing up a building and walking away in slow motion like a badass while a giant fireball ignites the sky. Aw yeah.
Just as we did with our other games, let's whip up a quick list of modifications and improvements we could make to Ticker Taker to make it a complete game.
Title Screen, Instructions, Credits these all go without saying.
Sound Effects you know how to hook these in, so why dontcha? The Ticker Taker cries out for a big wet *squish* whenever the heart hits the tray. You could also add the frantic clippity-clop sounds of Nurse Slipperfoot's Doc Martens slapping the linoleum as she makes her mad dash down the hallway.
Returning to the debate of creating an endless, always-lose game versus one the player can finish, what if you built a GUI element that depicted a 2D nurse icon running from point A to point B? All the player has to do is keep the heart aloft until the nurse icon reaches the end of the progress bar.
To add a bit of difficulty, you could add a little ECG heart monitor to the corner of the screen that beeps every time the player bounces the heart with enough force. Add a timer so that if x seconds elapse without the player bouncing the heart hard enough, the heart stops beating and the player loses the game. This will ensure that the player doesn't simply let the heart roll around on the tray until the nurse reaches the transplant ward.
The player's going to catch on pretty quickly that Nurse Slipperfoot is running in a circle! How about building two connected hallways, and making her run a figure-8 course for added visual variety?
The hallway is pretty flat and bland at the moment. Perhaps you could add spice to the environment by placing gurneys, IV stands, and even other patients in the level.
You may be wondering why the section on deploying your game has been squeezed into a tiny section at the very end of the book. That's because Unity makes it so darned simple to package up your game, that we don't need any more space. Here's how to do it:
In the menu, select File | Build Settings....
We need to add Scenes to this list that we want bundled into our game file. The first Scene we add to the list will be the first one Unity displays to our player, so that's where our preloader or title screen should normally go.
Because we have only one Scene in this game so far, click on the Add Current button to pop it into the list. In games with multiple Scenes, you can simply click-and-drag those Scenes into the list to add them to the build. Be sure to choose "Web Player" as your deployment preference if you'd like a file that can be played in a browser.
Click on the Build and Run button.
Unity asks where you want to save the
.unity3dgame file. Choose a folder and click on the Save button.
In the background, Unity cranks out a
.unity3dfile and an
.htmlfile to house it. Then Unity throws us to our default web browser and opens the HTML file. And there's our game, running beautifully within the browser.
To publish the game live to the world, just upload the
.unity3dfile and the
.htmlfile to your web host, or pop it onto one of the Unity game portals we looked at off the top of the book. Unity support grows on a daily basis, so there are bound to be many more places hosting Unity games by the time you read this paragraph.
Note that you can also deploy your game as a standalone version to run on the Mac and PC platforms. And if you spring for additional Unity licenses and development kits, you can deploy your content to a growing list of platforms, including iOS, the Xbox 360, the Playstation 3, the Wii, and Android.
The theme in all of this is "growth." While only a few years old, Unity has made a huge splash in the game development world by offering a suite of tools that blew the lid off of 3D browser-based gaming, while making it easier for people without serious C-based programming knowledge to develop for once-unfathomable devices.
It's a complete cliché, but practice really is the one thin line separating you from developing those big projects you put up in jars on the shelf at the beginning of the book. Start building a game with what you know. With each project, set a new attainable challenge for yourself. This book has taught you how to set lights in a flat-looking hallway environment. But you've heard this term "lightmap" when reading about 3D games and models. What's that all about? Well, why not build a new game using the skills you've already developed, and commit to incorporating one lightmapped object in it? When you finish the game, you'll have added one extra tool to your tool belt, and you'll have a new, finished game for your portfolio.
How do you make a skybox so that the corner seams are invisible? How do you make your player appear damaged when he steps in lava? What's normal mapping? How do you program an enemy to follow and shoot at the player? How do you create your own models, textures, and animations? How do you put a different hat, gun, or pair of pants on a character model? How do you detect when one Game Object is near another, without colliding?
With each new thing you want your game to do, you'll come up with a question. Too many questions could discourage you and sink your ship before it even gets out to sea. Pick one thing and lock onto it with your laser scope. Do whatever it takes to discover the answer to your question, the solution to your problem, and build that solution into your game. Problem solved. Dragon slain. Checkbox checked. You will slay many dragons/cuddle many kittens in your journey as a game developer, but there's no need to take on the entire dragon/kitten army all at once.
Be sure to check out the resources listed at the end of the book for places to turn to when you're stuck. You can also use that section to source new information when you're ready to add new tools to your tool belt.
If you're starting from scratch and you made it this far, I hope you've found Unity to be well within your ability to develop your own 3D and 2D games. If you're sidling over from another development tool like Flash, GameMaker Pro, or Unreal Engine, I hope this book has provided you with a sampling of the slick pipeline and process that Unity makes possible. A book like this can only ever scratch the surface of such an enormously powerful tool as Unity; if you've enjoyed what you've done with Unity so far, a fantastically supportive community and a deliciously deep development tool awaits you beyond the back cover of this book.