Simple Third Person Camera with Unity

Share:Tweet about this on TwitterShare on RedditPin on PinterestShare on FacebookShare on LinkedInShare on Google+

 

The third person camera

The camera in a game is the eye that the player use to see inside the virtual world created for the game itself. There are tons of different types of camera, but the one we are going to analyze is the third person camera (TPC from now on) which allows to see the main character moving around in the world. In our case it’s a camera that follows the player. Great examples of games that use this type of camera are Super Mario 64, Zelda – The Wind Waker, Metal Gear Solid and Assassin’s Creed.

The purpose of this article is to show how to do a camera system in Unity, with basic intelligence that follows the player and avoids to hit walls by doing auto-adjustments of the distance from the player and the ground as well. The final results are not the best ones and there are certainly other and better ways to do it, and yes, I know there are some improvements that can be done, but the main purpose of this demonstration is to give a simple starting point.

Setups

The Unity script is located here. The only things you have to do in order to test the script are:

  • In a new Unity scene add a third person controller. You can use the standard ones
  • Add at least one floor.
  • Add a child GameObject to the controller called “target” for example, and position it where you want the camera to look.
  • Add a child GameObject to the controller called “position” to identify the position of the character: some meshes may have the anchor point positioned differently, so in this way you can decide the correct position of the anchor point. It’s a optional step but it makes things a little easier.
  • Add the script to the camera and put the child objects just created under the camera script parameters in the inspector.

The code is commented and contains also a function to draw lines in the inspector to better see what is going on with the offsets and positions.

Camera position and movements

Without further ado, let’s begin with the fun stuff. The wanted position for the camera is a point that has a distanceUp and a distanceAway from the target identifying a specific point. Obviously if there is a rotation of the character, this point rotate along with it keeping its distances. Now this point is only the wanted position and we want the camera to follow this point with a little of smoothness. Simple, in positioning phase I’ve multiplied Time.deltaTime for a smoothness value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void Update()
{
        //For collision avoidance we need 2 values:
        // the distanceUp of the camera and the wanted position

        Vector3 characterOffset = m_target.position +
            new Vector3(0f, m_distanceUp - m_heightOffset, 0f);
           
        drawDebugLines (characterOffset);
        m_camPosWanted = m_target.position +
            (m_target.up * (m_distanceUp - m_heightOffset)) -
            (m_target.forward * m_distanceAway);

        collisionAvoidance(characterOffset, ref m_camPosWanted);

        //Positionig and orienting the camera
        transform.position = Vector3.Lerp(transform.position,
            m_camPosWanted, Time.deltaTime * m_smooth);
           
        transform.LookAt(m_target);
}

 

The collision avoidance

To keep the camera in the correct position and avoid walls that can hide the character or collide, the script makes some tests:

  • Wall avoidance: if there’s a collider near the back of the character or between the camera and the character, the camera takes the position of the collision point (improvable).
  • Ceiling avoidance: if there’s a collider above the character or above the camera, the camera changes its y coordinates to stay under the collider.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Camera Wall avoidance - raycast from the back of the character and from
//characterOffset to camPosWanted
if(Physics.Linecast(fromObject, toTarget, out m_hitWall) ||
   Physics.Raycast(m_characterPos.transform.position,
    -m_characterPos.transform.forward, out m_hitWall, 3.0f))
{
    toTarget = new Vector3(m_hitWall.point.x, toTarget.y, m_hitWall.point.z);
}

//Camera Ceil avoidance - raycast from the up of the character and from
//the up of the camera
if (Physics.Raycast(transform.position, Vector3.up,out m_hitUp, 1.0f) ||
    Physics.Raycast (m_characterPos.transform.position, Vector3.up, out m_hitUp, 2.0f))
{
    if (m_hitUp.collider.gameObject.layer != LayerMask.NameToLayer("Player"))
    {
        if (m_camPosWanted.y > m_hitUp.distance)
        {  
            Debug.Log("Ceil");
            m_heightOffset += 0.2f; //adjusting the height
        }
    }
}

 

Improvements

Improvements that can be surely done are:

  • Making a FSM and attaching it to the camera: for example the camera has state like colliding, shaking, bouncing and a following common state.
  • Improving the wall collision not to see parts of the world behind the wall.
  • Adding a colliding sphere to the camera.

 

Consider also to watching this GDC video on which a creator of the game Journey talks about common mistakes and tips on creating a third person camera.

Third Person Camera (Gist)

 

 

Game developer & designer. Unity 3D lover. Movie fanatic.

Game developer & designer. Unity 3D lover. Movie fanatic.