Unity is a major player in the cross platform game engine space with over 21 supported platforms, including Windows 10, MacOS, Linux, Android and iOS, all of which can use the same code base. In this workshop you will build "Orks with Forks (and Knives)" - a fun top down 2D game. Keep in mind Unity is not a 3D asset creation system, but instead a system in which you can arrange your assets, write code to animate, use physics, audio, and more. There are other software packages such as Autodesk Maya or Blender that can be used to 3D model, although Unity does have a built in terrain modeling system.
![alt](/Images/Orks Screenshot.PNG)
In this module, you will see how to:
- Use Unity's Editor to design a 2D level with sprites
- Handle User Input
- Work with the Camera
- Handle Input from Keyboard
- Move the player
- Setup an animation
- Test your game
The following is required to complete this module:
- Visual Studio Community 2015 or greater.
- Unity 5.3 or greater.
This module includes the following exercise:
Estimated time to complete this module: 60 minutes
Note: When you first start Visual Studio, you must select one of the predefined settings collections. Each predefined collection is designed to match a particular development style and determines window layouts, editor behavior, IntelliSense code snippets, and dialog box options. The procedures in this module describe the actions necessary to accomplish a given task in Visual Studio when using the General Development Settings collection. If you choose a different settings collection for your development environment, there may be differences in the steps that you should take into account.
In this exercise you will create your first Unity game. But first let's explore the Editor interface in Unity.
- The Hierarchy window contains everything in your scene. A scene is essentially a level in your game. When the game loads, it will load the first scene in your build settings (control-shift-b) or if you are working in the Editor, the current scene will load when you play test your game.
- The Scene tab contains your design surface for your level. Here you drag/drop objects and arrange your objects.
- Next is the Game window where you will see your game when test playing it.
- The Play bar or Tool bar allows you to play your game right in Unity without having to build externally. It also allows you to pause and run your game one frame at a time.
- After that is the Inspector window that has the properties of the currently selected Game Object.
- Finally the Project window is what contains all of the art, models, images, scripts, audio, and files (assets) that make up your project.
Unity's Asset Store allows you to buy (or get some for free) various assets related to your game.
To get started we need to open the starter Unity Project and find the scene file. Scenes are your levels in Unity. You will need to find your scene and open it to start working on it, just as you would have to find a web page to work on in a web project. The project may or may not load with it already open, so it is important to understand how to find them.
- Open Unity
- Choose "Open Project"
- Select the project folder on the desktop "OrksWithForks Starter"
- Unity will re-open and load the project.
- When Unity opens, find the scene file /Assets/Scenes/scene01 and double click it to open it.
Note the Play, Pause, and Frame Advance button on the toolbar. This allows you to play your game without having to manually compile and export a build. Mono is used as the runtime for your scripts (plus the native engine code) and Unity runs it right in the editor. When you click play, you'll go into Play Mode. This is a temporary testing mode and most changes you make will be lost, so it is important to know when you are in play mode.
Everything in your game is visible because of a camera. There are two camera types in Unity - Orthographic and Perspective. These are simply options on a camera component. Perspective cameras see the world as we do, while Orthographic cameras have no scaling with distance, which is good for 2D games. Also Orthographic camera size keeps a fixed height no matter what size screen we are running the game on. The only thing that varies is how much width is visible.
Orthographic Camera, note the height
Orthographic Camera, after changing screen width the height is still the same
-
Click play on the toolbar and run the game.
-
Move across the screen to the exit. Note the camera doesn't follow.
-
When you are done make sure you click play again to get out of play mode.
-
In the project window at the bottom, Navigate to /Scripts/
-
Drag and drop the CameraFollow.cs script onto the Camera Game Object in the hierarchy.
-
Click play again and notice how the camera now follows the character.
-
Get out of play mode.
-
Verify you are not in play mode. Press Control-S to save your scene. If you are in play mode you'll get an error.
-
In the hierarchy window, select the Main Camera game object. This acts as our eyes and ears. These are just components on this game object, an Audio Listener Component and a Camera Component.
-
In the Inspector window, change the size on the orthographic camera component to customize how much vertical height the user will see no matter the device they run it on.
The hierarchy window lists all of the game objects in the current scene. This window has been cleaned up quite a bit already but is still a bit messy. Some of the game objects should be organized better.
A game object can be a zombie, but it can also just be container for other objects. Every item in the hierarchy is a game object, which may or may not have any visible properties (like an invisibe spawn point). Let's organize this window a bit more by moving the enemies and some walls around.
-
Select the menu GameObject / Create Empty
-
Rename this new game object to "Enemies". Ensure you press Enter when done (don't just click away)
-
In the Hierarchy window only, drag and drop the Orks and Goblin onto this new game object.
Drag enemies onto the Enemies Game Object
-
In the Hierarchy window, locate the Environment game object. There are already a bunch of objects underneath it.
-
Next (still in the Hierarchy window), drag and drop all the 'walls' onto the "Environment" game object to clean up the view. You can control-click or click one and shift click another item, just as you would in Windows Explorer to select files.
-
Collapse the Environment and Enemies game objects to clean up the Hierarchy window.
Prefabs are a concept in Unity of a 'prefabricated object'. These are game object settings, components like physics and scripts. Our walls need to have physics on them.
The level is incomplete. The left edge has been removed. Add some level pieces from the /Prefabs folder to build out the level a bit more.
-
Use the /Sprites/Floors folder to drag/drop sprites into the Scene tab to draw out a floor plan. This folder is being used because we can simply run across an image. The case we need to handle is how we stop at a wall
-
Use the /Prefabs folder to drag/drop walls into the scene and draw the level. The walls are ordered by top/bottom after each center piece. Because of the top down scaling perspective view, the walls on each side of the center pieces have bricks directed in opposite directions. Enemies will move until they hit any object with a collider on it.
-
Now the tricky part. Vertex snapping. In order to get everything in place all night and neat we need to snap one vertex to the next closest vertex. Hold down V and mouse near the edge of a piece you want to snap to another.
Before we look at adding code to a more complete version of the player, let's take a look at some simple mechanics to make our player move. In Unity when we want to work with any game object we typically get a reference to a component via a GetComponent<> function call.
-
Open the scene /Scenes/SimplePlayer
-
Locate the game object "Player" in the Hierarchy window.
-
Look in the Inspector window at the components that bring this Game Object to life. We use various components in code to control an object
- Sprite Renderer - Displays a 2D image on the screen
- Animator - Controls the Sprite Renderer to play different images to animate this game object
- RigidBody 2D - Give this object mass and make it under the influence of gravity
- Circle Collider 2D - Give this object a shape the physics engine will use to simulate physics. The object will act like its a circle shape from a physics standpoint (collisions)
-
Click Play and notice that using the arrow keys we cannot control out player.
-
Get out of play mode
-
Open up /Scripts/SimplePlayer.cs and find the Start() method. Notice that here we ask Unity for this Game Object's RigidBody component by simply calling the following method. This component is how we'll eventually move our Player.
_rigidBody = GetComponent<Rigidbody2D>();
-
Back in Unity's Editor, Open Edit/Project Settings/Input. Note the Input settings for Horizontal are A/D or Left/Right arrow keys.
-
Locate the Update() method back in Visual Studio. Here we will need to read input (left/right up/down or ASDW keys). Replace the //TODO content in the Update() method so the code is complete as per below
void Update () { _horizontal = Input.GetAxis("Horizontal"); _vertical = Input.GetAxis("Vertical"); }
-
Our input has a value of -1 to +1 for both Horizontal and Veritcal. We can use these values read in Update() (which is where keyboard input should be read) and apply those values in FixedUpdate, which is where we typically do physics operations. Replace the //ToDo line with the method content below. This will set the velocity in meters/second of our game object. Note that we'll max out at 1 m/s in each direction because our input only goes from -1 to +1.
void FixedUpdate() { //Move the actual object by setting its velocity _rigidBody.velocity = new Vector2(_horizontal, _vertical); }
-
Save your changes and go back to Unity. There will be a brief pause while Unity compiles your code automatically, no work is needed. You can view any errors in the Console window. You shouldn't have any, this is just an FYI that errors will show up here and also in Visual Studio, although performing a build in Visual Studio is not necessary. Drag and Drop the SimplePlayer.cs script onto the Player game object.
-
Press Control-S to save your Unity scene changes and then click play to run the Unity project. Press the left/right up/down arrows or ASDW keys to move the character around.
Now that we see how to apply basic movement, let's add code to allow the character to play an animation that has been setup already. This animation will be triggered by "Fire1", which according to the input system is the left control key or the first mouse button (mouse 0 - ie left click). When we asked for Input previously, we used GetAxis. To check for buttons we can use GetButtonDown (or GetButton, GetButtonUp)
-
In the /Scripts/SimplePlayer.cs file, find the empty Update() method again and add the following code to it. This will run every frame and check for Fire1. It will only be true once and that's during the frame that runs and finds it held down. If the button is held down, this will not repeat, although that is possible to do with GetButton()
void Update() { //existing code here //Now add this code if (Input.GetButtonDown("Fire1")) { _animator.SetTrigger("Attack"); } }
-
Save your code and go back to Unity. There will be a few second pause while your code is compiled by Unity.
-
Click Play to test out the changes. You should now get a walking animation when you move and an attack animation when you press the left mouse button or left control key.
In Unity, we can detect when one object has come within range of another object in several ways, one of them being what's called a Trigger. The other is a collider. A collider will stop one object from passing through another. A trigger is a special case of a collider that allows objects to pass through but gives us the opportunity to be notified in code when object A intersects with object B. A collider/trigger is simply a predefined shape (sphere, box, capsule, etc) that the physics engine uses. It doesn't matter what an object physically looks like to determine how it behaves physically, that is determined by the collider/trigger shape.
-
Find a coin in the scene and click on it. It may help to press T to select the 2D tool.
-
Right click on the coin in the Hierarchy and choose "Select Prefab". This coin is a prefab, that's why it is blue in the Hierarchy window. This is an instance of a shared object in your project folder. If you change the shared object, you'll change every instance of that coin.
-
In the Project Window, ensure the coin is highlighted. Note - we're talking about the project window, not the Hierarchy window. Click the Add Component button and type in Circle.
-
On the newly added component, check the box for "Is Trigger". This will turn it from an immovable object to something you can run through (ie - pick up)
-
Notice that any coin you click on now has this trigger on it.
-
Open the /Scenes/scene01 and find the Player game object near the top of the hierarchy. Note that this game object has a PlayerController script which is a more completed version of the SimplePlayer script.
-
Open the /Scripts/PlayerController.cs file either by double clicking on it or double clicking on it from the Inspector for the Player game object
-
Find the OnTriggerEnter2D method. This will get called when the player runs over any objects with a 2D trigger on it, like we created for the coin.
-
Back in Unity's Editor, find any coin in the scene or the /Prefabs/coin they are all made from. In the Inspector note that each coin has a PickupProperties.cs script on it that simply contains its value in points. We can see this in the Editor. Since code is just another component on a game object, we can ask Unity for these values.
-
In Visual Studio, uncomment the code for the first TODO. This will increment our coin score when we run over a coin. We know we run over a coin because it has a tag. A tag is just text we can use to identity an object (just like you can in Windows Forms and XAML). You can create your own tags easily and then assign them in a dropdown list for an object. Here's an image showing the coin tag that is set. Creating a new tag is just a matter of selecting "Add Tag". Your code should now look like this
if (collision.gameObject.tag == "Coin") { //Get its coin score by asking for the value of PickupProperties.CoinAmount //That value is visible from the Editor, it's just a public variable in PickupProperties. var pickupProperties = collision.gameObject.GetComponent<PickupProperties>(); CoinUp(pickupProperties.CoinAmount); //TODO - destroy game object we just picked up }
-
In Visual Studio find the "TODO - destroy game object we just picked up" and replace it with the code shown below. Our completed block of code now looks like the following:
if (collision.gameObject.tag == "Coin") { //Get its coin score by asking for the value of PickupProperties.CoinAmount //That value is visible from the Editor, it's just a public variable in PickupProperties. var pickupProperties = collision.gameObject.GetComponent<PickupProperties>(); CoinUp(pickupProperties.CoinAmount); Destroy(collision.gameObject); }
-
Save your code and go back to Unity's Editor and play your game. When you run over coins now you should see them disappear and your coin score increase.
Some existing animations have already been set up for our fearless hero. Animations in Unity simply control components over time via point in time snapshots called keyframes. Animations require two things - an Animator component on the game object which in turn points to an animation controller.
The items below are:
-
The selected player with its Components showing in the Inspector window.
-
The Animator component which points to 3
-
The Animation Controller file. This contains the sequence of animations to play. Think of it as a flow chart for animations
-
Each rectangle represents a different animation to play. We'll create a new one momentarily.
-
The arrows are called the transitions that move between each animation. It's the properties on these transitions that define when to play each animation.
Let's go ahead and add a Walk animation to the player.
- Navigate to the /Sprites/Hero/Walk folder
- In the folder press Control-A to select all of the images
- Drag and drop them onto the Player game object in the hierarchy. If prompted to create a file name it "Walk". This will be automatically created to contain the animation keyframes to cycle through each sprite.
-
That last step creates a Walk.anim file with animation data in it. That data is visible in the Animation window (Menu item Windows/Animation) once you select the Player.
-
Now let's double click on the hero animation controller file. Ensure the Player is selected and double click on "Hero"
-
Note there's now a new Walk state in our Animation Controller. Drag it next to soldier_attack
-
Next we'll configure the options to play this animation. Right click on soldier_idle and select Make Transition. This will give you an arrow to dock on Walk.
-
Repeat the same process from Walk to soldier_idle and between Walk and soldier_attack so we have bidirectional arrows between every state.
-
Let's create a boolean variable called "Walk" the animation system will use. When it becomes true, we'll move from idle to walk. Click the parameters tab on the top left and then click the plus sign. Select Bool and name it Walk (case sensitive)
-
Next we need to tell our transitions (the arrows, remember?) to use this variable to signal when to go from Idle to Walk. Click on the arrow line going from soldier_idle to walk. It will turn blue.
-
On the right hand side of the screen under Conditions click the plus sign to Add, and change it to Walk / True. We uncheck "Has Exit Time" because this animation can be interrupted at any time to go back to idle. We also choose 0 for Transition Duration because we're not blending between 2D animations during our transition (we can't blend 2d images and have something that looks good) like we can with 3D model animations, so we typically set this to 0 for 2D animations.
-
Do the exact same thing again on the arrow going from Walk to Idle, except make Walk / False. This says when we set Walk = false, go back to playing our Idle sprites.
-
Configure our Walk<-->Attack. We don't need to create another parameter for this, we already have one called Attack on our parameters tab that was created for this lab. This is a trigger, which is acts like a boolean until it's been used by a transition and then goes back to false.
Let's configure Walk->Soldier_Attack like we did Idle->Walk except we'll use the Attack condition. Click the transition from Walk->Soldier_Attack and configure the options as shown.
-
Lastly configure Attack to Walk. Pay careful attention. Set the condition to Walk / true (we only want to walk again if walk is true otherwise we'll go to idle instead).
We want our Attack animation to complete before we're allowed to go back to walk so we need to check off "Has Exit Time" and set Exit Time=1, which means the entire animation must play. Then change Transition Offset to 0.
-
Our animation controller is all set to go. However we need code to set our Walk variable. Attack has been taken care of already in the code. When a user moves the horizontal or vertical input will be nonzero so we can set Walk = true if that's the case.
Open /Scripts/PlayerController.cs and navigate to the bottom of the Update() method. Uncomment the line that sets our Boolean parameter in the animation system and save your changes.
_animator.SetBool("Walk", _horizontal != 0 || _vertical != 0); ````
- Go back to Unity and run your game. You should now get walk animations when you move. You may notice little glitches such as moving while attacking. Look at the code in the completed lab for handling various cases like that.
This lab took you through several aspects of Unity, and while there are always more exciting things to learn, we've covered a good number of subjects such as:
- The Editor Layout
- Working with 2D Sprites
- Testing your game in the editor (Play Mode)
- Working with a trigger
- Working with Prefabs
- Destroying game objects
- Organizing game objects
- Using the animation system to create sprite based animations
For additional learning resources, check out