Unity: Camera Smooth Follow

  • Requirement: Unity
  • Language: C#
  • Difficulty: Easy
  • Written By: Lee Zhi Eng
  • Last update: 14 Jul 2019

Introduction

In this tutorial, we will learn how to make a camera to follow a game object in Unity. We will cover a few methods that are commonly used in games. Some methods are simple and direct, yet some others provide more options for customization but rather complicated to set up.

Let’s get started!

Camera Parenting

Perhaps one of the easiest methods to make a camera to follow an object around is to make the game object the parent of the camera. This way, the camera will follow exactly the movement and rotation of its parent object.

The downside of this method is that the movement feels very rigid. This is because the camera will follow exactly the movement speed and rotation speed of the parent object on all axis. Another disadvantage of this method is that you can hardly customize the behavior of your camera; for example, only rotate on a certain axis; or zoom in and zoom out depending on the game state.

However, it is still worth mentioning the method as you might want just that – a simple camera movement that follows exactly it’s parent object. It really depending on what game you’re making, so no judging here.

Let’s follow the steps below to learn how to set up basic camera parenting.

1. First, identify which game object you want your camera to follow. For example, I want my Main Camera to follow the Player object:

Hierarchy panel

2. Then, in the Hierarchy panel, drag and drop the Main Camera on top of the Player object to apply the parent-child relationship. In this case, the Main Camera will be made the child of the Player object:

Parent-child relationship changed

If you run your game now, you should see the camera moves and turns exactly as its parent object:

Camera Parenting method

You should have noticed the main problem with this method after watching the video above – the player may start feeling dizzy after playing the game for a while!

Follow Transform

Another method would be asking the camera to follow only the position and not rotation. For this method we’ll have to start writing come C# code.

1. Create a new C# script by right-clicking on the Project panel and select Create 🡒 C# Script. Name this script as GameCamera and open it with Visual Studio by double-clicking on it.

2. Once you have opened the script with Visual Studio, the first thing we need to do is to declare the variables, namely player and offset:

public class GameCamera : MonoBehaviour
{
    public UnityEngine.Transform player;
    Vector3 offset;

As you can see, only the player variable is a public variable and not the offset variable. The player variable is the target object’s transform property that carries its position and rotation data. The offset variable on the other hand, is the position difference/offset between the player and the camera, which can be illustrated as below, shown in red color:

Position offset in a nutshell

Since the offset value is being automatically set, and does not need to be set from the editor, it’s not declared as a public variable.

We’ll calculate the offset value when the game starts, so that we can just position the camera anyhow we like in the editor and it will start following the player exactly the same distance when the game starts. This saves a lot of time without having to manually key in the distance between the camera and player everytime we want to make changes.

3. Therefore, let’s add in the code below to the Start() function for calculating the offset value at game start:

void Start()
{
    offset = transform.position - player.position;
}

4. After that, update the camera’s position to its destination by adding the player’s position with the offset we calculated earlier:

void Update()
{
    transform.position = player.position + offset;
}

If you run the game now, you should see the camera is following the player’s position but not its rotation:

Follow transform method

This method is all nice and well, but you can go even further by making the camera “lazy” and slightly delays its movement. This will produce a more convincing third person perspective.

Move Towards

In this part of the tutorial, you’ll learn 3 different methods for making the camera to smoothly following the player: Move Towards, Linear Interpolation and Smooth Damp.

1. Let’s start with the first method, Move Towards. First, remove the following line of code which we have written in our previous example:

transform.position = player.position + offset;

2. Then, replace it with the following code:

float speed = 3.0f;
transform.position = Vector3.MoveTowards(transform.position, player.position + offset, Time.deltaTime * speed);

In the code above, we called the Vector3.MoveTowards() function to move the position toward its destination over a period of time, which we can then control the movement speed by multiplying the speed variable with the game’s delta time. By multiplying the delta time, the movement speed will be consistent regardless of the frame rate. The result can be seen below:

Move towards method

Now the camera follows the player at a slightly delayed speed, which looks pretty good. However, you can notice from the video above that the camera stops instantly when reaching its destination, which feels very rigid.

To solve this problem, we’ll use another method called Linear Interpolation.

Linear Interpolation

Linear Interpolation is a function used to gradually move a vector value between 2 points. In Unity, the function can be found in the Vector3 class, and therefore, we can write our movement code like this:

float speed = 1.0f;
transform.position = Vector3.Lerp(transform.position, player.position + offset, Time.deltaTime * speed);

The Lerp() function looks pretty much like the MoveTowards() function, but it gives a nice slow in and slow out effects, which looks a lot better

Linear interpolation method

Smooth Damp

Additionally, we can also use another method called Smooth Damp method. This method gradually changes a vector toward a desired goal over time, which is quite similar to Linear Interpolation. However, you can also get the velocity of the camera movement from this function, which is great if you need the data for your gameplay logic.

1. The code for Smooth Damp method is also really simple. First, declare a Vector3 variable called velocity. This variable is used to store the velocity output in later step:

Vector3 velocity = Vector3.zero;

2. Then, we call the Vector3.SmoothDamp() function to move the camera toward its destination:

transform.position = Vector3.SmoothDamp(transform.position, player.position + offset, ref velocity, 0.1f);

The function looks very similar to MoveTowards() and Lerp(), but the third variable is actually an output variable that gives you the current velocity of the camera, which we saves to the velocity variable declared earlier.

The fourth input variable is the estimated time it will take to arrive the destination. There is an optional fifth variable which is max speed, but we don’t put any for now.

3. Finally, we can print out the velocity value at the Console panel by calling print():

print(velocity);

If you run the game now, you should notice no difference in terms of the smoothness of the movement, but you can now see the velocity of the camera being printed on the Console panel:

Print out velocity

Source Code

The full source code looks like the following. You can comment/uncomment the code to try out the different methods:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameCamera : MonoBehaviour
{
    public UnityEngine.Transform player;
    Vector3 offset;

    // Start is called before the first frame update
    void Start()
    {
        offset = transform.position - player.position;
    }

    // Update is called once per frame
    void Update()
    {
        // Follow Transform
        //transform.position = player.position + offset;

        // Move Towards
        //float speed = 3.0f;
        //transform.position = Vector3.MoveTowards(transform.position, player.position + offset, Time.deltaTime * speed);

        // Linear Interpolation
        //float speed = 1.0f;
        //transform.position = Vector3.Lerp(transform.position, player.position + offset, Time.deltaTime * speed);

        // Smooth Damp
        Vector3 velocity = Vector3.zero;
        transform.position = Vector3.SmoothDamp(transform.position, player.position + offset, ref velocity, 0.1f);
        print(velocity);
    }
}

Leave a Reply