Camera always behind player in Unity3d

18,007

Solution 1

You need to move your camera position based on sphere movement direction -

public GameObject player;
private Vector3 offset;

float distance;
Vector3 playerPrevPos, playerMoveDir;

// Use this for initialization
void Start () {
    offset = transform.position - player.transform.position;

    distance = offset.magnitude;
    playerPrevPos = player.transform.position;
}

void LateUpdate () {

    playerMoveDir = player.transform.position - playerPrevPos;
    playerMoveDir.normalize();
    transform.position = player.transform.position - playerMoveDir * distance;

    transform.LookAt(player.transform.position);

    playerPrevPos = player.transform.position;
}

Edit 2: To fix flickering camera, try this -

void LateUpdate () {
    playerMoveDir = player.transform.position - playerPrevPos;
    if (playerMoveDir != Vector3.zero)
    {
        playerMoveDir.normalize();
        transform.position = player.transform.position - playerMoveDir * distance;

        transform.position.y += 5f; // required height

        transform.LookAt(player.transform.position);

        playerPrevPos = player.transform.position;
    }
}

Solution 2

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

public class CameraFollow : MonoBehaviour {

    public GameObject player;
    public float cameraDistance = 10.0f;

    // Use this for initialization
    void Start () {
    }

    void LateUpdate ()
    {
        transform.position = player.transform.position - player.transform.forward * cameraDistance;
        transform.LookAt (player.transform.position);
        transform.position = new Vector3 (transform.position.x, transform.position.y + 5, transform.position.z);
    }
}

Solution 3

My solution (based on @brennon-provencher answer) with smoothness and auto offset:

public class CameraFollow : MonoBehaviour
{
    public GameObject target;
    public float speed = 5;

    Vector3 offset;

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

    void LateUpdate()
    {
        // Look
        var newRotation = Quaternion.LookRotation(target.transform.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, speed * Time.deltaTime);

        // Move
        Vector3 newPosition = target.transform.position - target.transform.forward * offset.z - target.transform.up * offset.y;
        transform.position = Vector3.Slerp(transform.position, newPosition, Time.deltaTime * speed);
    }
}
Share:
18,007
HB1963
Author by

HB1963

Updated on June 04, 2022

Comments

  • HB1963
    HB1963 almost 2 years

    I'm struggling with this for quit some time now. I have GameObject, being a sphere, which is my player on a 3d Terrain. I have a Camera which is always on a fixed distance from the player, follows it where it goes with below script:

    public GameObject player;
    private Vector3 offset;
    
    
    // Use this for initialization
    void Start () {
        offset = transform.position - player.transform.position;
    
    
    }
    
    void LateUpdate () {
    
        transform.position = player.transform.position + offset;
    }
    

    So far so good. However what I actually want is that the camera rotates with the player, so it always looks into the direction where the sphere is moving, but always stays behind the player at the same fixed distance, so that the player is always visible in the camera view.

    There are a lot of scripts available, but the problem with the onces I've seen so far is that the camera indeed rotate with the player, but because the player actually is a rolling sphere the camera view is rolling and turning as well.

    The best script I found so far is below, but this one has the same problem as the other onces, the camera rolls with the player.

    public Transform target;
    public float distance = 3.0f;
    public float height = 3.0f;
    public float damping = 5.0f;
    public bool smoothRotation = true;
    public bool followBehind = true;
    public float rotationDamping = 10.0f;
    
    void Update () {
        Vector3 wantedPosition;
        if(followBehind)
            wantedPosition = target.TransformPoint(0, height, -distance);
        else
            wantedPosition = target.TransformPoint(0, height, distance);
    
        transform.position = Vector3.Lerp (transform.position, wantedPosition, Time.deltaTime * damping);
    
        if (smoothRotation) {
            Quaternion wantedRotation = Quaternion.LookRotation(target.position - transform.position, target.up);
            //Quaternion ownRotation = Quaternion.RotateTowards;
            transform.rotation = Quaternion.Slerp (transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
        }
        else transform.LookAt (target, target.up);
    }
    

    Can anyone help me with this please?

  • HB1963
    HB1963 almost 7 years
    Thx Mukesh. Nearly there. The camera follows the player and always stays behind. Unfortunately for some reason the camera view is flickering now. Any idea?
  • Mukesh Saini
    Mukesh Saini almost 7 years
    Is camera always flickering or only when sphere is not moving?
  • HB1963
    HB1963 almost 7 years
    Hi Mukesh, camera is always flickering. It looks like as if it is showing a view from two differerent zoom levels.
  • Mukesh Saini
    Mukesh Saini almost 7 years
    Try checking if the player movement is recorded as Vector3.zero because in that case camera position will be same as player position. I've updated the Edit section in answer for this.
  • HB1963
    HB1963 almost 7 years
    Hi Mukesh, been away for a while. This did it. Thx very much. One last question. The camera is now on player level, how can I make it looking "over the shoulder" of the player, so floating above and behind the player?
  • Mukesh Saini
    Mukesh Saini almost 7 years
    I've updated the answer to give it some height. You can make the height configurable in unity inspector or store the initial camera height in start function and then use that.
  • HB1963
    HB1963 almost 7 years
    I'm afraid that doesn't work. Building end in error: "Cannot modify the return value of 'UnityEngine.Transform.positon' because it is not a variable"
  • Mukesh Saini
    Mukesh Saini almost 7 years
    In UnityEngine.Transform.positon you are missing an i after t in the spelling of transform's position variable.
  • HB1963
    HB1963 almost 7 years
    Solved it. float yy = transform.position.y; yy += 5f; transform.position = new Vector3 (transform.position.x, yy, transform.position.z);
  • Someone Somewhere
    Someone Somewhere about 4 years
    this is great if you want the camera to follow. In my case, I always want the camera to look at an object from the objects' right side" Vector3 newPosition = target.transform.position - target.transform.right * offset.x - target.transform.up * offset.y;
  • Shn
    Shn over 3 years
    This is working as of 8/6/2020. Short and sweet answer!