Unity 2017 Mobile Game Development

5 (6 reviews total)
By John P. Doran
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Building Your Game

About this book

Unity has established itself as an overpowering force for developing mobile games. If you love mobile games and want to learn how to make them but have no idea where to begin, then this book is just what you need. This book takes a clear, step-by-step approach to building an endless runner game using Unity with plenty of examples on how to create a game that is uniquely your own.

Starting from scratch, you will build, set up, and deploy a simple game to a mobile device. You will learn to add touch gestures and design UI elements that can be used in both landscape and portrait mode at different resolutions. You will explore the best ways to monetize your game projects using Unity Ads and in-app purchases before you share your game information on social networks. Next, using Unity’s analytics tools you will be able to make your game better by gaining insights into how players like and use your game. Finally, you’ll learn how to publish your game on the iOS and Android App Stores for the world to see and play along.

Publication date:
November 2017
Publisher
Packt
Pages
360
ISBN
9781787288713

 

Chapter 1. Building Your Game

As we start off on our journey building mobile games using the Unity game engine, it's important that readers are familiar with the engine itself before we dive into the specifics of building things for mobile platforms. Although there is a chance that you've already built a game and want to transition it to mobile, there will also be readers who haven't touched Unity before, or may have not used it in a long time. This chapter will act as an introduction to newcomers, a refresher for those coming back, and will provide some best practices for those who are already familiar with Unity.

In this chapter, we will build a 3-D endless runner game in the same vein as Imangi Studios, LLC's Temple Run series. In our case, we will have a player who will run continuously in a certain direction, and will dodge obstacles that come in their way. We can also add additional features to the game easily, as the game will endlessly have new things added to it.

 

Chapter overview


Over the course of this chapter, we will create a simple project in Unity, which we will be modifying over the course of this book to make use of features commonly seen in mobile games. While you may skip this chapter if you're already familiar with Unity, I find it's also a good idea to go through the project so that you know the thought processes behind why the project is made in the way that it is, so you can keep it in mind for your own future titles.

Your objectives

This chapter will be split into a number of topics. It will contain a simple, step-by-step process from beginning to end. Here is the outline of our tasks:

  • Project setup
  • Creating the player
  • Improving scripts using attributes
  • Having the camera follow the player
  • Creating a basic tile
  • Making the game endless
  • Creating obstacles
 

Setting up the project


Now that we have our goals in mind, let's start building our project:

  1. To get started, open Unity on your computer. For the purpose of this book, we will use Unity 2017.2.0f3, but the steps should work with minimal changes in future versions.

Note

If you would like to download the exact version used in this book, and there is a new version out, you can visit Unity's download archive at https://unity3d.com/get-unity/download/archive.

  1. From startup, we'll opt to create a new project by clicking on the New button.
  2. Next, under Project name* put in a name (I have chosen MobileDev) and make sure that 3D is selected. If Enable Unity Analytics is enabled (the check to the left of it says On), click on the Enable Unity Analytics button again in order to disable it for the time being; we will add it ourselves later on when we go through Chapter 5, Advertising with Unity Ads. Afterwards, click on Create project and wait for Unity to load up:
  1. After it's finished, you'll see the Unity Editor pop up for the first time:

  1. If your layout doesn't look the same as in the preceding screenshot, you may go to the top-right section of the toolbar and select the drop-down menu there that reads Layers. From there, select Default from the options presented.

Note

If this is your first time working with Unity, then I highly suggest that you read the Learning the Interface section of the Unity Manual, which you can access at https://docs.unity3d.com/Manual/LearningtheInterface.html.

 

Creating the player


Now that we have Unity opened up, we can actually start building our project. To get started, let's build a player that will always move forward. Let's start with that now:

  1. Let's create some ground for our player to walk on. To do that, let's go to the top menu and select GameObject | 3D Object | Cube.
  2. From there, let's move over to the Inspector window and change the name of the object to Floor. Then, on the Transform component, set the Position to (0, 0, 0), which we can either type in, or we can right-click on the Transform component and then select the Reset Position option.
  3. Then, we will set the Scale to (7, 0.1, 10):

In Unity, by default, 1 unit of space in Unity is representative of 1 meter in real life. This will make the floor longer than it is wide (X and Z), and we have some size on the ground (Y), so the player will collide and land on it because we have a Box Collider component attached to it.

  1. Next, we will create our player, which will be a sphere. To do this, we will go to Game Object | 3D Object | Sphere.
  1. Rename the sphere to Player and set the Transform component's Position to (0, 1, -4):

This will place the ball slightly above the ground, and shifts it back to near the starting point. Note that the camera object (you can see a camera icon to point it out) is pointing toward the ball by default because it is positioned at 0, 1, -10.

  1. We want the ball to move, so we will need to tell the physics engine that we want to have this object react to forces, so we will need to add a Rigidbody component. To do so, go to the menu and select Component | Physics | Rigidbody. To see what happens now, let's click on the Play button that can be seen in the middle of the top toolbar:

As you can see in the preceding screenshot, you should see the ball fall down onto the ground when we play the game.

Note

You can disable/enable having the Game tab take the entire screen when being played by clicking on the Maximize On Play button at the top, or by right-clicking on the Game tab and then selecting Maximize.

  1. Click on the Play button again to turn the game off and go back to the Scene tab, if it doesn't happen automatically.

We want to have the player move, so in order to do that, we will create our own piece of functionality in a script, effectively creating our own custom component in the process.

  1. To create a script, we will go to the Project window and select Create | Folder on the top-left corner of the menu. From there, we'll name this folder Scripts. It's always a good idea to organize our projects, so this will help with that.

Note

If you happen to misspell the name, go ahead and select the object and then single-click on the name and it'll let you rename it.

  1. Double-click on the folder to enter it, and now you can create a script by going to Create | C# Script and renaming this to PlayerBehaviour (no spaces).

Note

The reason I'm using the "behaviour", "spelling" instead of "behavior" is that all components in Unity are children of another class called MonoBehaviour, and I'm following Unity's lead in that regard.

  1. Double-click on the script to open up the script editor (IDE) of your choice and add the following code to it:
using UnityEngine; 

public class PlayerBehaviour : MonoBehaviour 
{ 
    // A reference to the Rigidbody component 
    private Rigidbody rb; 

    // How fast the ball moves left/right 
    public float dodgeSpeed = 5; 

    // How fast the ball moves forwards automatically 
    public float rollSpeed = 5; 

   // Use this for initialization 
   void Start () 
   { 
        // Get access to our Rigidbody component 
        rb = GetComponent<Rigidbody>(); 
   } 

   // Update is called once per frame 
   void Update () 
   { 
        // Check if we're moving to the side 
        var horizontalSpeed = Input.GetAxis("Horizontal") * dodgeSpeed; 
        rb.AddForce(horizontalSpeed, 0, rollSpeed); 
   } 
}

In the preceding code, we have a couple of variables that we will be working with. The rb variable is a reference to the game object's Rigidbody component that we added previously. It gives us the ability to make the object move, which we will use in the Update function. We also have two variables dodgeSpeed and rollSpeed, which dictates how quickly the player will move when moving left/right, or when moving forward, respectively.

Since our object has only one Rigidbody component, we assign rb once in the Start function, which is called when the game starts, as long as the game object attached to this script is enabled.

Then, we use the Update function to check whether our player is pressing keys to move left or right as based on Unity's Input Manager system. By default, the Input.GetAxis function will return to us a negative value moving to -1 if we press A or the left arrow. If we press the right arrow or D, we will get a positive value up to 1 returned to us, and the input will move toward a 0 if nothing is pressed. We then multiply this by dodgeSpeed in order to increase the speed so that it is easier to be seen.

Note

For more information on the Input Manager, check out https://docs.unity3d.com/Manual/class-InputManager.html.

Finally, once we have that value, we will apply a force to our ball's horizontalSpeed units on the X-axis and rollSpeed in the Z-axis.

  1. Save your script, and return to Unity.
  1. We will now need to assign this script to our player by selecting the Player object in the Hierarchy window, and then in the Inspector window, drag and drop the PlayerBehaviour script from the Project window on top of the Player object. If all goes well, we should see the script appear on our object, as follows:

Note that when writing scripts if we declare a variable as public, it will show up in the Inspector window for us to be able to set it. We typically set a variable as public when we want designers to tweak the values for gameplay purposes.

  1. Save your scene by going to File | Save Scene. Create a new folder called Scenes and save your scene as Gameplay. Afterward, play the game and use the left and right arrows to see the player moving according to your input, but no matter what, moving forward by default:
 

Improving our scripts with attributes and XML comments


We could stop working with the PlayerBehaviour class script here, but I want to touch on a couple of things that we can use in order to improve the quality and style of our code. This becomes especially useful when you start building projects in teams, as you'll be working with other people--some of them will be working on code with you, and then there are designers and artists who will not be working on code with you, but will still need to use the things that you've programmed.

When writing scripts, we want them to be as error-proof as possible. Making the rb variable private starts that process, as now the user will not be able to modify that anywhere outside of this class. We want our teammates to modify dodgeSpeed and rollSpeed, but we may want to give them some advice as to what it is and/or how it will be used. To do this in the Inspector window, we can make use of something called an attribute.

Using attributes

Attributes are things we can add to the beginning of a variable, class, or function declaration, which allow us to attach an additional functionality to them. There are many of them that exist inside Unity, and you can write your very own as well, but, right now, we'll talk about the ones that I use most often.

The Tooltip attribute

If you've used Unity for a period of time, you may have noted that some components in the Inspector window, such as the Rigidbody, have a nice feature--if you move your mouse over a variable name, you'll see a description of what the variables are and/or how to use them. The first thing you'll learn is how we can get the same effect in our own components by making use of the Tooltip attribute. If we do this for the dodgeSpeed and rollSpeed variables, it will look something like this:

[Tooltip("How fast the ball moves left/right")] 
public float dodgeSpeed = 5; 

[Tooltip("How fast the ball moves forwards automatically")] 
public float rollSpeed = 5; 

Save the preceding script and return to the editor:

Now, when we highlight the variable using the mouse and leave it there, the text we placed will be displayed. This is a great habit to get into, as your teammates can always tell what it is that your variables are being used for.

Note

For more information on the Tooltip attribute, check out, https://docs.unity3d.com/ScriptReference/TooltipAttribute.html.

The Range attribute

Another thing that we can use to protect our code is the Range attribute. This will allow us to specify a minimum and maximum value for a variable. Since we want the player to always be moving forward, we may want to restrict the player from moving backward. To do that, we can add the following highlighted line of code:

    [Tooltip("How fast the ball moves forwards automatically")] 
[Range(0, 10)]
    public float rollSpeed = 5; 

Save your script, and return to the editor:

We have now added a slider beside our value, and we can drag it to adjust between our minimum and maximum values. Not only does this protect our variable, it also makes it so our designers can tweak things easily by just dragging them around.

The RequireComponent attribute

Currently, we are using the Rigidbody component in order to create our script. When working as a team member, others may not be reading your scripts, but are still expected to use them when creating gameplay. Unfortunately, this means that they may do things that have unintended results, such as removing the Rigidbody component, which will cause errors when our script is run. Thankfully, we also have the RequireComponent attribute, which we can use to fix this.

It looks something like this:

using UnityEngine; 

[RequireComponent(typeof(Rigidbody))] 
public class PlayerBehaviour : MonoBehaviour 

By adding this attribute, we state that when we add this component to a game object and it doesn't have a Rigidbody attached to its game object, the component will be added automatically. It also makes it so that if we were to try to remove the Rigidbody from this object, the editor will warn us that we can't, unless we remove the PlayerBehaviour component first. Note that this works for any class extended from MonoBehaviour; just replace Rigidbody with whatever it is that you wish to keep.

Now, if we go into the Unity editor and try to remove the Rigidbody component by right-clicking on it in the Inspector and selecting Remove Component, the following message will be seen:

This is exactly what we want, and this ensures that the component will be there, allowing us not to have to include if-checks every time we want to use a component.

XML comments

Note that previously we did not use a Tooltip attribute on the private rb variable. Since it's not being displayed in the editor, it's not really needed. However, there is a way that we can enhance that as well, making use of XML comments. XML comments have a couple of nice things that we get when using them instead of traditional comments, which we were using previously. When using the variables/functions instead of code in Visual Studio, we will now see a comment about it. This will help other coders on your team have additional information and details to ensure that they are using your code correctly.

XML comments look something like this:

/// <summary> 
/// A reference to the Rigidbody component 
/// </summary> 
private Rigidbody rb;

It may appear to be a lot more writing is needed to use this format, but I did not actually type the entire thing out. XML comments are a fairly standard C# feature, so if you are using MonoDevelop or Visual Studio and type ///, it will automatically generate the summary blocks for you (and the param tags needed, if there are parameters needed for something like a function).

Now, why would we want to do this? Well, now, if you select the variable in Intellisense, it will display the following information to us:

This is a great help for when other people are trying to use your code and it is how Unity's staff write their code. We can also extend this to functions and classes to ensure that our code is more self-documented.

Unfortunately, XML comments do not show up in the Inspector, and the Tooltip attribute doesn't show info in the editor. With that in mind, I used Tooltips for public instructions and/or things that will show up in the Inspector window, and XML comments for everything else.

Note

If you're interested in looking into XML comments more, feel free to check out: https://msdn.microsoft.com/en-us/library/b2s063f7.aspx.

Putting it all together

With all of the stuff we've been talking about, we can now have the final version of the script, which looks like the following:

using UnityEngine; 

/// <summary> 
/// Responsible for moving the player automatically and  
/// reciving input. 
/// </summary> 
[RequireComponent(typeof(Rigidbody))] 

public class PlayerBehaviour : MonoBehaviour 
{ 
    /// <summary> 
    /// A reference to the Rigidbody component 
    /// </summary> 
    private Rigidbody rb; 

    [Tooltip("How fast the ball moves left/right")] 
    public float dodgeSpeed = 5; 


    [Tooltip("How fast the ball moves forwards automatically")] 
    [Range(0, 10)] 
    public float rollSpeed = 5; 

    /// <summary> 
    /// Use this for initialization 
    /// </summary> 
    void Start () 
   { 
        // Get access to our Rigidbody component 
       rb = GetComponent<Rigidbody>(); 
   } 

    /// <summary> 
    /// Update is called once per frame 
    /// </summary> 
    void Update () 
   { 
        // Check if we're moving to the side 
       var horizontalSpeed = Input.GetAxis("Horizontal") *  
                              dodgeSpeed; 

        // Apply our auto-moving and movement forces 
      rb.AddForce(horizontalSpeed, 0, rollSpeed); 
   } 
} 

I hope that you also agree that this makes the code easier to understand and better to work with.

 

Having the camera following our player


 

Currently, our camera stays in the same spot while the game is going on. This does not work very well for this game, as the player will be moving more the longer the game is going on. There are two main ways that we can move our camera. We can just move the camera and make it a child of the player, but that will not work due to the ball's rotation. Due to that, we will likely want to use a script instead. Thankfully, we can modify how our camera looks at things fairly easily, so let's go ahead and fix that next:

  1. Go to the Project window and create a new C# script called CameraBehaviour. From there, use the following code:
using UnityEngine; 

/// <summary> 
/// Will adjust the camera to follow and face a target 
/// </summary> 
public class CameraBehaviour : MonoBehaviour 
{ 
    [Tooltip("What object should the camera be looking at")] 
    public Transform target; 

    [Tooltip("How offset will the camera be to the target")] 
    public Vector3 offset = new Vector3(0, 3, -6); 

    /// <summary> 
    /// Update is called once per frame 
    /// </summary> 
    void Update ()                                              
   { 
        // Check if target is a valid object 
        if (target != null) 
        { 
            // Set our position to an offset of our target 
            transform.position = target.position + offset; 

            // Change the rotation to face target 
            transform.LookAt(target); 
        } 

   } 
} 
  1. Save the script and dive back into the Unity Editor. Select the Main Camera object in the Hierarchy window. Then, go to the Inspector window and add the CameraBehaviour component to it. You may do this by dragging and dropping the script from the Project window onto the game object or by clicking on the Add Component button at the bottom of the Inspector window, typing in the name of our component, and then clicking on Enter to confirm once it is highlighted.
  1. Afterward, drag and drop the Player object from the Hierarchy window into the Target property of the script in the Inspector window:

  1. Save the scene, and play the game:

The camera now follows the player as it moves. Feel free to tweak the variables and see how it effects the look of the camera to get the feel you'd like best for the project.

 

Creating a basic tile


We want our game to be endless, but in order to do so, we will need to have pieces that we can spawn to build our environment; let's do that now:

  1. To get started, we will first need to create a single piece for our runner game. To do that, let's first add some walls to the floor we already have. From the Hierarchy window, select the Floor object and duplicate it by pressing Ctrl + D in Windows or command + D on Mac. Rename this new object as Left Wall.

 

  1. Change the Left Wall object's Transform component by adjusting the Scale to (1, 2, 10). From there, select the Move tool by clicking on the button with arrows on the toolbar or by pressing the W key.

Note

For more information on Unity's built-in hotkeys, check out: https://docs.unity3d.com/Manual/UnityHotkeys.html.

  1. We want this wall to match up with the floor, so hold down the V key to enter the Vertex Snap mode.

In the Vertex Snap mode, we can select any of the vertices on a mesh and move it to the same position of another vertex on a different object. This is really useful for making sure that objects don't have holes between them.

  1. With the Vertex Snap mode on, select the inner edge and drag it until it hits the edge of the floor.

Note

For more info on moving objects through the scene, including more details on Vertex Snap mode, check out https://docs.unity3d.com/Manual/PositioningGameObjects.html.

  1. Then, duplicate this wall and put an other on the other side, naming it Right Wall:

As you can see in the preceding screenshot, we now protect the player from falling off the left and right edges of the play area. Due to how the walls are set up, if we move the floor object, the walls will move as well.

Note

For info on moving Unity's camera or navigating to the scene view, check out: https://docs.unity3d.com/Manual/SceneViewNavigation.html.

The way this game is designed, after the ball rolls past a single tile, we will no longer need it to be there anymore. If we just leave it there, the game will get slower over time due to us having so many things in the game environment using memory, so it's a good idea to remove assets we are no longer using. We also need to have some way to figure out when we should spawn new tiles to continue the path the player can take.

  1. Now, we also want to know where this piece ends, so we'll add an object with a Trigger collider in it. Select GameObject | Create Empty and name this object Tile End.
  2. Then, we will add a Box Collider component to our Tile End object. Under the Box Collider in the Inspector window, set the Size to (7, 2, 1) to fit the size of the space the player can walk in. Note that there is a green box around that space showing where collisions can take place. Set the Position property to (0, 1, 10) to reach past the end of our tile. Finally, check the Is Trigger property so that the collision engine will turn the collider into a trigger, which will be able to run code events when it is hit, but will not prevent the player from moving:

Like I mentioned briefly before, this trigger will be used to tell the game that our player has finished walking over this tile. This is positioned past the tile due to the fact that we want to still see tiles until they pass what the camera can see. We'll tell the engine to remove this tile from the game, but we will dive more into that later on in the chapter.

  1. Now that we have all of the objects created, we want to group our objects together as one piece that we can create duplicates of. To do this, let's create an Empty Game Object by going to GameObject | Create Empty and name the newly created object to Basic Tile. 
  1. Then, go to the Hierarchy window and drag and drop the Floor, Tile End, Left Wall, and Right Wall objects on top of it to make them children of the Basic Tile object. 
  2. Currently, the camera can see the start of the tiles, so to fix that, let's set the Basic Tile's Position to (0, 0, -5) so that the entire tile will shift back.
  3. Finally, we will need to know at what position we should spawn the next piece, so create another child of Basic Tile, give it the name, Next Spawn Point, and set its Position to (0, 0, 5).

Note

Note that when we modify an object that has a parent, the position is relative to the parent, not its world position.

Notice that the spawn point is on the edge of our current title. Now we have a single tile that is fully completed. Instead of duplicating this a number of times by hand, we will make use of Unity's concept or prefabs.

Prefabs, or prefabricated objects, are blueprints of game objects and components that we can turn into files, which can be duplicates. There are other interesting features that prefabs have, but we will discuss them as we make use of them.

  1. From the Project window, go to the Assets folder and then create a new folder called Prefabs. Then, drag and drop the Basic Tile object from the Hierarchy window to the Project window inside the Prefabs folder. If the text on the Basic Tile name in the Hierarchy window becomes blue, we will know that it was made correctly:

With that, we now have a tile prefab that we can create duplicates of the tile through code to extend our environment.

 

Making it endless


Now that we have a foundation, let's now make it so that we can continue running instead of stopping after a short time:

  1. To start off with, we have our prefab, so we can delete the original Basic Tile in the Hierarchy window by selecting it and then pressing the Delete key.
  1. We need to have a place to create all of these tiles and potentially manage information for the game, such as the player's score. In Unity, this is typically referred to as a GameController. From the Project window, go to the Scripts folder and create a new C# script called GameController.
  2. Open the script in your IDE, and use the following code:
using UnityEngine;

/// <summary> 
/// Controls the main gameplay 
/// </summary> 

public class GameController : MonoBehaviour
{
    [Tooltip("A reference to the tile we want to spawn")]
    public Transform tile;

    [Tooltip("Where the first tile should be placed at")]
    public Vector3 startPoint = new Vector3(0, 0, -5);

    [Tooltip("How many tiles should we create in advance")]
    [Range(1, 15)]
    public int initSpawnNum = 10;

    /// <summary> 
    /// Where the next tile should be spawned at. 
    /// </summary> 
    private Vector3 nextTileLocation;

    /// <summary> 
    /// How should the next tile be rotated? 
    /// </summary> 
    private Quaternion nextTileRotation;

    /// <summary> 
    /// Used for initialization 
    /// </summary> 

    void Start()
    {
        // Set our starting point 
        nextTileLocation = startPoint;
        nextTileRotation = Quaternion.identity;

        for (int i = 0; i < initSpawnNum; ++i)
        {
            SpawnNextTile();
        }
    }

    /// <summary> 
    /// Will spawn a tile at a certain location and setup the next position 
    /// </summary> 

    public void SpawnNextTile()
    {
        var newTile = Instantiate(tile, nextTileLocation, 
                                  nextTileRotation);

        // Figure out where and at what rotation we should spawn 
        // the next item 
        var nextTile = newTile.Find("Next Spawn Point");
        nextTileLocation = nextTile.position;
        nextTileRotation = nextTile.rotation;
    }
} 

This script will spawn a number of tiles, one after another, based on the tile and initSpawnNum properties.

  1. Save your script and dive back into Unity. From there, create a new Empty game object and name it Game Controller. Drag and drop it to the top of the Hierarchy window. For clarity's sake, go ahead and reset the position if you want to. Then, attach the Game Controller script to the object and then set the Tile property by dragging and dropping the Basic Tile prefab from the Project window into the Tile slot:
  1. Save your scene and run the project:

Great, but now we will need to create new objects after these, but we don't want to spawn a crazy number of these at once. It's better that once we reach the end of a tile, we create a new tile and remove it. We'll work on optimizing this more later, but that way we always have around the same number of tiles in the game at one time.

  1. Go into the Project window and create a new script called TileEndBehaviour, using the following code:
using UnityEngine; 

/// <summary> 
/// Handles spawning a new tile and destroying this one  
/// upon the player reaching the end 
/// </summary> 
public class TileEndBehaviour : MonoBehaviour 
{ 
    [Tooltip("How much time to wait before destroying " + 
             "the tile after reaching the end")] 
    public float destroyTime = 1.5f; 

    void OnTriggerEnter(Collider col) 
    { 
        // First check if we collided with the player 
        if (col.gameObject.GetComponent<PlayerBehaviour>()) 
        { 
            // If we did, spawn a new tile 
            GameObject.FindObjectOfType<GameController>().SpawnNextTile(); 

            // And destroy this entire tile after a short delay 
            Destroy(transform.parent.gameObject, destroyTime); 
        } 
    } 
} 
  1. Now, to assign it to the prefab, we can go to the Project window and then go into the Prefabs folder. From there, click on the arrow beside the Basic Tile to open up its objects and then add a Tile End Behaviour component to the Tile End object:
  1. Save your scene and play.

You'll note now that as the player continues to move, new tiles will spawn as you continue; if you switch to the Scene tab while playing, you'll see that as the ball passes the tiles they will destroy themselves:

 

Creating obstacles


It's great that we have some basic tiles, but it's a good idea to give the player something to do or, in our case, something to avoid. In this section, you'll learn how to customize your tiles to add obstacles for your player to avoid:

  1. So, just like we created a prefab for our basic tile, we will create a single obstacle through code. I want to make it easy to see what the obstacle will look like in the world and make sure that it's not too large, so I'll drag and drop a Basic Tile prefab back into the world.
  1. Next, we will create a cube by going to GameObject | 3D Object | Cube. We will then name this object Obstacle. Change the Y Scale to 2 and position it above the platform at (0, 1, .025):
  1. We can then play the game to see how this'll work:
  1. As you can see in the preceding screenshot, the player gets stopped, but nothing really happens. In this instance, we want the player to lose when he hits this and then restart the game; so, to do that, we'll need to write a script. From the Project window, go to the Scripts folder and create a new script called ObstacleBehaviour. We'll use the following code:
using UnityEngine; 
using UnityEngine.SceneManagement; // LoadScene 

public class ObstacleBehaviour : MonoBehaviour { 

    [Tooltip("How long to wait before restarting the game")] 
    public float waitTime = 2.0f; 

    void OnCollisionEnter(Collision collision) 
    { 
        // First check if we collided with the player 
        if (collision.gameObject.GetComponent<PlayerBehaviour>()) 
        { 
            // Destroy the player 
            Destroy(collision.gameObject); 

            // Call the function ResetGame after waitTime has passed 
            Invoke("ResetGame", waitTime); 
        } 
    } 

    /// <summary> 
    /// Will restart the currently loaded level 
    /// </summary> 
    void ResetGame() 
    { 
        // Restarts the current level 
        SceneManager.LoadScene(SceneManager.GetActiveScene().name); 
    } 
} 
  1. Save the script and return to the editor, attaching the script to the Obstacle property we just created.
  2. Save your scene and try the game:

As you can see in the preceding screenshot, once we hit the obstacle, the player gets destroyed, and then after a few seconds, the game starts up again. You'll learn to use particle systems and other things to polish this up, but at this point, it's functional, which is what we want.

You may note that when the level is reloaded, there are some lighting issues in the editor. The game will still work correctly when exported, but this may be a minor annoyance.

  1. (Optional) To fix this, go to Window | Lighting | Settings. Uncheck the Auto Generate option from there, and click on Generate Lighting--once it is finished, our issue should be solved.

Note

It isn't an issue with our game, but if you employ the fix above in your own titles, you must remember to go here every time you alter a game level and rebuild the lightmap for it to be updated correctly.

  1. Now that we know it works correctly, we can make it a prefab. Just as we did with the original tile, go ahead and drag and drop it from the Hierarchy into the Project tab and into the Prefabs folder:
  1. Next, we will remove the Obstacle, as we'll spawn it upon creating the tile.
  1. We will make markers to indicate where we would possibly like to spawn our obstacles. Duplicate the Next Spawn Object object and move the new one to (0, 1, 4). We will then rename the object as Center. Afterwards, click on the icon on the top left of the blue box and then select the blue color. Upon doing this, you'll see that we can see the text inside the editor, if we are close to the object (but it won't show up in the Game tab by default):
  1. We want a way to get all of the potential spawn points we will want in case we decide to extend the project in the future, so we will assign a tag as a reference to make those objects easier to find. To do that at the top of the Inspector window, click on the tag dropdown and select Add Tag. From the menu that pops up, press the + button and then name it ObstacleSpawn.

Note

For more information on tags and why we'd want to use them, check out https://docs.unity3d.com/Manual/Tags.html.

  1. Go ahead and duplicate this twice and name the others Left and Right, respectively, moving them 2 units to the left and right of the center to become other possible obstacle points:
  1. Note that these changes don't affect the original prefab, by default; that's why the objects are currently black text. To make this happen, select Basic Tile, and then in the Inspector window under the Prefab section, click on Apply.
  2. Now that the prefab is set up correctly, we can go ahead and remove it by selecting it and pressing Delete.
  3. We then need to go into the GameController script and modify it to have the following code:
using UnityEngine;
using System.Collections.Generic; // List 

/// <summary> 
/// Controls the main gameplay 
/// </summary> 

public class GameController : MonoBehaviour
{
    [Tooltip("A reference to the tile we want to spawn")]
    public Transform tile;

    [Tooltip("A reference to the obstacle we want to spawn")]
    public Transform obstacle;

    [Tooltip("Where the first tile should be placed at")]
    public Vector3 startPoint = new Vector3(0, 0, -5);

    [Tooltip("How many tiles should we create in advance")]
    [Range(1, 15)]
    public int initSpawnNum = 10;

    [Tooltip("How many tiles to spawn initially with no obstacles")]
    public int initNoObstacles = 4;

    /// <summary> 
    /// Where the next tile should be spawned at. 
    /// </summary> 
    private Vector3 nextTileLocation;

    /// <summary> 
    /// How should the next tile be rotated? 
    /// </summary> 
    private Quaternion nextTileRotation;

    /// <summary> 
    /// Used for initialization 
    /// </summary> 
    void Start()
    {
        // Set our starting point 
        nextTileLocation = startPoint;
        nextTileRotation = Quaternion.identity;

        for (int i = 0; i < initSpawnNum; ++i)
        {
            SpawnNextTile(i >= initNoObstacles);
        }
    }

    /// <summary> 
    /// Will spawn a tile at a certain location and setup the next 
    position 
    /// </summary> 
    public void SpawnNextTile(bool spawnObstacles = true)
    {
        var newTile = Instantiate(tile, nextTileLocation, 
                                  nextTileRotation);

        // Figure out where and at what rotation we should spawn 
        // the next item 
        var nextTile = newTile.Find("Next Spawn Point");
        nextTileLocation = nextTile.position;
        nextTileRotation = nextTile.rotation;

        if (!spawnObstacles)
            return;

        // Now we need to get all of the possible places to spawn the 
        // obstacle 
        var obstacleSpawnPoints = new List<GameObject>();

        // Go through each of the child game objects in our tile 
        foreach (Transform child in newTile)
        {
            // If it has the ObstacleSpawn tag 
            if (child.CompareTag("ObstacleSpawn"))
            {
                // We add it as a possibilty 
                obstacleSpawnPoints.Add(child.gameObject);
            }
        }

        // Make sure there is at least one 
        if (obstacleSpawnPoints.Count > 0)
        {
            // Get a random object from the ones we have 
            var spawnPoint = obstacleSpawnPoints[Random.Range(0, 
                                          obstacleSpawnPoints.Count)];

            // Store its position for us to use 
            var spawnPos = spawnPoint.transform.position;

            // Create our obstacle 
            var newObstacle = Instantiate(obstacle, spawnPos, 
                                          Quaternion.identity);

            // Have it parented to the tile
            newObstacle.SetParent(spawnPoint.transform);
        }
    }
}

Note that we modified the SpawnNextTile function to now have a default parameter set to true, which will tell us if we want to spawn obstacles or not. At the beginning of the game, we may not want the player to have to start dodging immediately, but we can tweak the value to increase or decrease the number we are using.

  1. Save the script and go back to the Unity editor. Then, assign the Obstacle variable in the Inspector with the obstacle prefab we created previously.
  2. It's a bit hard to see things currently due to the default light settings, so let's go to the Hierarchy window and select the Directional Light object.

A directional light acts similarly to how the sun works on earth, shining everywhere from a certain rotation.

  1. With the default settings the light is too bright, making it difficult to see, so we can just change the Color to be darker. I used the following:

  1. Save your scene and play the game:

Note

For more information on directional lights and the other lighting types that Unity has, check out: https://unity3d.com/learn/tutorials/topics/graphics/light-types?playlist=17102.

As you can see in the preceding screenshot, we now have a number of obstacles for our player to avoid, and due to how the player works, he will gradually get faster and faster, causing the game to increase in difficulty over time.

 

Summary


There we have it! A solid foundation, but just that, a foundation. However, that being said, we covered a lot of content in this chapter. We discussed how to create a new project in Unity, we built a player that will move continuously, as well as take inputs to move horizontally. We then discussed how we can use Unity's attributes and XML comments to improve our code quality and help us when working with teams. We also covered how to have a moving camera. We created a tile-based level design system, where we created new tiles as the game continued, randomly spawning obstacles for the player to avoid.

Throughout this book, we will explore more that we can do to improve this project and polish it, while adapting it to being the best experience possible on mobile platforms. However, before we get to that, we'll actually need to figure out how to deploy our projects.

About the Author

  • John P. Doran

    John P. Doran is a passionate and seasoned technical game designer, software engineer, and author based in Peoria, Illinois.

    For over a decade, John has gained extensive hands-on expertise in game development, working in a variety of roles, ranging from game designer to lead UI programmer. Additionally, John has worked in game development education teaching in Singapore, South Korea, and the United States. To date, he has authored over 10 books pertaining to game development.

    John is currently an instructor in residence at Bradley University. Prior to his present ventures, he was an award-winning videographer.

    Browse publications by this author

Latest Reviews

(6 reviews total)
The book on mobile development with Unity at Amazon was getting pretty bad reviews, while this one was getting great! Recognizing that Packt was the publisher, and not minding an ebook instead of a paperback, came over here to fine that not only was it available, but on a huge sale price! Best purchase I've made in tech books in a long time. The book is well structured, and laid out for developing on iOs as well as Android, and walks you through step by step how to setup your project for both. Highly recommend!
Google Play de uygulamalarım var. Onları destekler niteliğinde okuyorum, daha kısa, öz yollardan çözüm vermiş, bana çok faydalı oldu.
cool thanks for the help Thanks

Recommended For You

Unity Artificial Intelligence Programming - Fourth Edition

Learn and Implement game AI in Unity 2018 to build smart game environments and enemies with A*, Finite State Machines, Behavior Trees and NavMesh.

By Dr. Davide Aversa and 2 more
Unity 2018 Cookbook - Third Edition

Develop quality game components and solve common gameplay problems with various game design patterns

By Matt Smith
Hands-On Game Development Patterns with Unity 2019

Write maintainable, fault-tolerant, and cleaner game codes by understanding the standard development patterns and battle-tested practices.

By David Baron
Unity 2018 Artificial Intelligence Cookbook - Second Edition

Explore various recipes to build games using popular artificial intelligence techniques and algorithms such as Navmesh navigation A*, DFS, and UCB1

By Jorge Palacios