Creating an infinite 3D runner game in Unity (like Temple Run, Subway Surfers), part 2

This is the second part of  an infinite 3D runner game tutorial. If you haven’t read the first part, you’re highly encouraged to do it by clicking here. As always, you can find the source code here on GitHub and play the game here on a WebGL enabled browser.

The levels

In the second and last part of the tutorial, we’ll see how the two game levels were built. We’ll begin with the “straight paths” level.

Straight Paths Level

Let’s take a look at the objects contained in our game hierarchy.

1
GameObject hierarchy in the straight paths level.

First, there is the straight path game object which, by nature, is wider than the one in the “rotated paths” level. The path is a prefab (as designated by its blue color) and all subsequent paths will be clones of this one. Scene also contains some cubical shaped 3D objects (named Cubes), which act as floor of our path. It also contains the NewPathSpawn game object (a simple location in the 3D space), and some other locations called SpawnPoints. The SpawnPoints are positions in which new stuff will be generated. This stuff can be either a candy, or obstacle, or nothing at all.

Recall that Max runs from path to path. As we are not generating all paths at the beginning of the game (because we want to save on memory and mainly because we do not know how far in the game the player will proceed, i.e. how many paths to generate), we need a mechanism to generate the N+1 path, where N is the path that Max currently steps on. We’ve used a simple trigger BoxCollider to implement this. When Max collides with it, a new path is generated via the PathSpawnCollider script (described in a while). In the straight paths level, the new path is instantiated in the “NewPathSpawn” position, which conveniently happens to be positioned at the far end of the current path.

2
When the player collides with the PathSpawnCollider, a new path is generated on the NewPathSpawn position.
3
The NewPathSpawnPosition, where a new straight path will be instantiated.

The Character game object holds our Camera and the Max model. It also has a Character Controller component (which allows us to easily move our object) and a CharacterSidewaysMovement script (described below). Making the Character game object move will move both Camera and Max (since they are child game objects). This is the classic way of making 3rd person games, since in this way, camera will always be at the same position during the game, behind and a bit higher than Max.

The Canvas game object holds our simple UI (two Text objects) whereas the Directional Light is a simple light and the ScriptHolder game object holds our GameManager singleton script, which was described in the first part of the tutorial.

PathSpawnColliderScript

This script is used on both levels in order to generate the next path, following the one Max is currently running on.


public class PathSpawnCollider : MonoBehaviour {

    public float positionY = 0.81f;
    public Transform[] PathSpawnPoints;
    public GameObject Path;
    public GameObject DangerousBorder;

Script begins by declaring some public variables, to be set outside the script in the Unity editor.
– PositionY is used to properly place the redBorder on the Y axis
– The PathSpawnPoints array is used to host the locations that the next path and borders will be instantiated. In the “straight paths” level the array will have only one member (since we’ll only instantiate the next path) whereas in the “rotated paths” level the array will hold three locations, in one of which there will be the new path and in the rest two there will be the red borders that will kill Max upon collision
– The Path object holds the path prefab
– The DangerousBorder array holds the RedBorder prefab in the “rotated paths” level whereas it is null in the “straight path” level (where we do not need it)


  void OnTriggerEnter(Collider hit)
    {
        //player has hit the collider
        if (hit.gameObject.tag == Constants.PlayerTag)
        {
            //find whether the next path will be straight, left or right
            int randomSpawnPoint = Random.Range(0, PathSpawnPoints.Length);
            for (int i = 0; i < PathSpawnPoints.Length; i++)
            {
                //instantiate the path, on the set rotation
                if (i == randomSpawnPoint)
                    Instantiate(Path, PathSpawnPoints[i].position, PathSpawnPoints[i].rotation);
                else
                {
                    //instantiate the border, but rotate it 90 degrees first
                    Vector3 rotation = PathSpawnPoints[i].rotation.eulerAngles;
                    rotation.y += 90;
                    Vector3 position = PathSpawnPoints[i].position;
                    position.y += positionY;
                    Instantiate(SpawnBorder, position, Quaternion.Euler(rotation));
                }
            }

        }
    }

When Max collides with the PathSpawnCollider game object, game engine randomly chooses whether the next path will be straight, left or right. In the case of the “straight paths” level, we have only one entry in the PathSpawnPoints array (which corresponds to the straight location), so randomSpawnPoint will be 0 and the next path will be instatiated at the straight location. In the “rotated paths” level, we instatiate the next path on the chosen location and we also instantiate the RedBorder prefabs on the other two locations, while we are rotating them by 90 degrees to make them fit properly.

Read More »