Combining camera look and orbit

First I had a simple script on my camera that just did this:

float rotLeftRight = Input.GetAxis ("Mouse X") * mouseSensitivity1P;
player.transform.Rotate (0, rotLeftRight, 0);

So in order to turn the camera, I simply turned the player to which the camera was attached.

Now I wanted a camera that adjusted more to what the player was doing and allow for a few things:

  • When the player is moving, the camera moves behind him and stays there
  • When the player is not moving, he must be able to turn the camera all the way around the model, in order to see its face or to look behind it without turning the player.
  • For the camera to only rotate when the player holds the right mouse button.

After many hours I finally came up with this:

using UnityEngine;

public class OrbitCamera : MonoBehaviour
{
    public Transform lookAtTarget;
    GameObject player;
    Vector3 desiredPosition = Vector3.zero;

    float camDistance = 10.0f;
    float minCamDistance = 5.0f;
    float maxCamDistance = 15.0f;
    float mouseX = 0.0f;
    float mouseY = 0.0f;
    float rotLeftRight = 0;
    float mouseSensitivity = 5.0f;
    float mouseWheelSensitivity = 5.0f;
    float yMin = 0.0f;
    float yMax = 70.0f;

    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
        camDistance = Vector3.Distance(lookAtTarget.transform.position, gameObject.transform.position);
    }

    void LateUpdate()
    {
        HandlePlayerInput();
        HandlePosition();
    }

    void HandlePlayerInput()
    {
        if (Input.GetButton("Fire2"))
        {
            mouseX += Input.GetAxis("Mouse X") * mouseSensitivity;
            mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
            rotLeftRight = Input.GetAxis("Mouse X") * mouseSensitivity;
        }

        // Handle and clamp scroll
        camDistance = Mathf.Clamp(camDistance - (Input.GetAxis("Mouse ScrollWheel") * mouseWheelSensitivity), minCamDistance, maxCamDistance);

        // Clamp Y axis
        mouseY = Mathf.Clamp(mouseY, yMin, yMax);
    }

    void HandlePosition()
    {
        // Calculate position
        Vector3 direction = new Vector3(0, 0, -camDistance);
        Quaternion rotation = Quaternion.Euler(mouseY, mouseX, 0);
        desiredPosition = lookAtTarget.position + (rotation * direction);

        transform.position = new Vector3(desiredPosition.x, desiredPosition.y, desiredPosition.z);

        if (Input.GetAxisRaw("Vertical") != 0)
        {
            //This causes the flickering movement
            player.transform.Rotate(0, rotLeftRight, 0);
        }
        transform.LookAt(lookAtTarget);
    }
}

Note that I have a different script handling movement, simply back and forth and left and right, which is placed on the player. The camera script is on the camera which is a child of the player.

Now, I can’t figure out this. How can I get rid of the jagged movement (because setting the player.transform like this and then using LookAt() causes flickering).

If any more skilled programmer could help figure this out that would be great.

I’m not familiar with what you are trying to do (I understand the concept but have never attempted to implement such a thing) However, when I am stuck my first port of call is usually (for the problem you are having)

http://wiki.unity3d.com/index.php/Scripts/Controllers

The Camera Controllers section will give you examples you can use or compare with your code.

For example, the MouseOrbitInfiniteRotateZoom controller might be of use to you.

http://wiki.unity3d.com/index.php/MouseOrbitInfiteRotateZoom

I apologize if you have already looked at these resources previously and decided they are not of use.

Hey guys,

thanks for the help. Reading up on all the tips made me come up with this finally and it works very well, though there may be inefficiencies or such. I moved the camera off of the player gameobject and wrote a first person and third person script all in one. The only thing to do now is handle clipping of the camera in third person.

using UnityEngine;
using System.Collections;

public class CameraTransform : MonoBehaviour
{
    GameObject playerGO;
    PlayerMovement PM;
    bool inFirstPersonMode = true;

    //Shared in 1P / 3P
    float mouseX = 0f;
    float mouseY = 0f;
    float mouseSensitivity = 5f;

    //1P only
    float yMin1P = -35f;
    float yMax1P = 85f;

    //3P Only
    float camDistance = 10f;
    float minCamDistance = 5f;
    float maxCamDistance = 15f;
    float mouseWheelSensitivity = 5f;
    float yMin3P = 0f;
    float yMax3P = 70f;


    void Start()
    {
        playerGO = GameObject.FindGameObjectWithTag("Player");
        PM = playerGO.GetComponent<PlayerMovement>();
        //Once to handle wierd flicking of the cam if not done
        HandleRotation();
    }

    void LateUpdate()
    {
        //Let player toggle camera mode
        if (Input.GetKeyDown(KeyCode.T))
            Swap1P3P();

        HandleRotation();
    }

    void Swap1P3P()
    {
        inFirstPersonMode = !inFirstPersonMode;

        if (inFirstPersonMode)
        {
            transform.localPosition = new Vector3(0f, 0f, 0f);
            mouseX = 0f;
            mouseY = 0f;
        }
        else
        {
            transform.localPosition = new Vector3(0f, 3f, -5f);
            mouseX = 0f;
            mouseY = 0f;
        }

        //Once to set up
        HandleRotation();
    }

    void HandleRotation()
    {
        if (inFirstPersonMode)
        {
            if (Input.GetMouseButton(1))
            {
                mouseX += Input.GetAxis("Mouse X") * mouseSensitivity;
                playerGO.transform.rotation = Quaternion.Euler(new Vector3(playerGO.transform.rotation.eulerAngles.x,
                                                                         mouseX,
                                                                         playerGO.transform.rotation.eulerAngles.z));

                mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
                mouseY = Mathf.Clamp(mouseY, yMin1P, yMax1P);
                transform.localRotation = Quaternion.Euler(mouseY, 0, 0);
            }

            //Keep the camera stuck at the players transform
            transform.position = new Vector3(playerGO.transform.position.x,
                                             playerGO.transform.position.y + 1.8f,
                                             playerGO.transform.position.z);

            //Rotate the camera as per the input (which doesn't change if mouse button 1 is not held)
            transform.rotation = Quaternion.Euler(mouseY,
                                                  playerGO.transform.rotation.eulerAngles.y,
                                                  playerGO.transform.rotation.eulerAngles.z);
        }
        if (!inFirstPersonMode)
        {
            if (Input.GetMouseButton(1))
            {
                mouseX += Input.GetAxis("Mouse X") * mouseSensitivity;
                mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
            }

            // Handle and clamp scroll
            camDistance = Mathf.Clamp(camDistance - (Input.GetAxis("Mouse ScrollWheel") * mouseWheelSensitivity),
                                      minCamDistance,
                                      maxCamDistance);

            // Clamp Y axis
            mouseY = Mathf.Clamp(mouseY, yMin3P, yMax3P);

            // Calculate position
            Vector3 offset = new Vector3(0, 0, -camDistance);
            Quaternion rotation = Quaternion.Euler(mouseY, mouseX, 0);
            transform.position = playerGO.transform.position + (rotation * offset);

            //Don't turn the player if he is not moving
            if (Input.GetAxisRaw("Horizontal") != 0 ||
                Input.GetAxisRaw("Vertical") != 0 )
            {
                playerGO.transform.rotation = Quaternion.Euler(playerGO.transform.rotation.eulerAngles.x,
                                                               mouseX,
                                                               playerGO.transform.rotation.eulerAngles.z);
            }

            //Rotate the camera as per player input
            transform.rotation = Quaternion.Euler(playerGO.transform.rotation.eulerAngles.x,
                                                  mouseX,
                                                  playerGO.transform.rotation.eulerAngles.z);

            //face the player object (this will cause the orbit)
            transform.LookAt(playerGO.transform);
        }
    }
}