Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Camera / Simple Controller from Scratch

Discussion in 'Scripting' started by bigmisterb, Jun 13, 2016.

  1. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    I am posting this for a couple of reasons. 1) so that people can learn some basics of how to script. (not only a camera, but other things) and 2) for posterity (I am getting old and tend to forget things.)

    So let me begin by telling you what I want; I want an orbital camera that can be used as a third person camera as well.

    Getting Started:
    We need a plane in the scene, about 20x20, A capsule (default one) the default camera and default light.

    We will be creating this in C#, so I created a script called SimpleController, and edited it in. This script will be designed to be put on the capsule, and operate it using WASD for movement.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class SimpleController : MonoBehaviour
    6. {
    7.  
    8.     // first lets start by defining the camera
    9.     Camera camera;
    10.  
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.         // lets find the camera and put it on the variable.
    15.         camera = Camera.main;
    16.         if (camera == null) camera = Camera.allCameras[0];
    17.     }
    18. }
    19.  

    OK, now lets add some stuff to handle the mouse.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. // now lets make sure that the capsule has the proper CharacterController
    6. // I put this here, so I can reduce the code you have to read later...
    7. [RequireComponent(typeof(CharacterController))]
    8. public class SimpleController : MonoBehaviour
    9. {
    10.     Camera camera;
    11.  
    12.     // lets store the X and Z values from the mouse here
    13.     float x, y;
    14.  
    15.  
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.         camera = Camera.main;
    20.         if (camera == null) camera = Camera.allCameras[0];
    21.  
    22.         // lets also capture the current angles;
    23.         var euler = camera.transform.eulerAngles;
    24.         x = euler.x;
    25.         y = euler.y;
    26.     }
    27. }
    28.  

    OK, now lets make it work. To do this, we add an update method that will be handled every frame.
    Code (csharp):
    1.  
    2.     void Update()
    3.     {
    4.         // lets now capture the mouse
    5.         // remember:
    6.         // Mouse X is side to side, this means that Mouse X actually should control the Y axis of the camera
    7.         // Mouse Y is up and down, and should control Axis Y. (using a negative value)
    8.         // lastly, 20 is the sensitivity to the mouse.
    9.         x -= Input.GetAxis("Mouse Y") * 20;
    10.         y += Input.GetAxis("Mouse X") * 20;
    11.  
    12.         // put the camera in the position of the head of the capsule.
    13.         // VERY IMPORTANT!!!
    14.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    15.  
    16.         // assign the rotation to the camera.
    17.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    18.     }
    19.  
    Now, with all of this together, we can apply the script to the capsule and it will actually look


    Next, lets limit the X so that we can't look upside down.
    Code (csharp):
    1.  
    2.     void Update()
    3.     {
    4.         x -= Input.GetAxis("Mouse Y") * 20;
    5.         y += Input.GetAxis("Mouse X") * 20;
    6.  
    7.         // add the clamp to the X only
    8.         x = ClampAngle(x, -60, 60);
    9.  
    10.  
    11.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    12.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    13.     }
    14.  
    15.  
    16.     // this is a clamping method designed to allow -180 to 180 clamping
    17.     float ClampAngle(float angle, float min, float max) {
    18.         angle %= 360;
    19.         if (angle > 180) angle -= 360;
    20.         return Mathf.Clamp(angle, min, max);
    21.     }
    22.  
    now, lets make the capsule look in that direction. Remember that we must always be vertical.
    Code (csharp):
    1.  
    2.     void Update()
    3.     {
    4.         x -= Input.GetAxis("Mouse Y") * 20;
    5.         y += Input.GetAxis("Mouse X") * 20;
    6.  
    7.         x = ClampAngle(x, -60, 60);
    8.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    9.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    10.  
    11.         // get the look at point which is in front of the camera.
    12.         var lookAt = camera.transform.TransformPoint(Vector3.forward);
    13.         // re-assign the y position to that of the capsule.
    14.         lookAt.y = transform.position.y;
    15.         // now make the capsule look at the point.
    16.         transform.LookAt(lookAt);
    17.     }
    18.  
    OK, now lets look at movement WASD...
    Code (csharp):
    1.  
    2.     void Update()
    3.     {
    4.         x -= Input.GetAxis("Mouse Y") * 20;
    5.         y += Input.GetAxis("Mouse X") * 20;
    6.  
    7.         x = ClampAngle(x, -60, 60);
    8.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    9.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    10.  
    11.         var lookAt = camera.transform.TransformPoint(Vector3.forward);
    12.         lookAt.y = transform.position.y;
    13.         transform.LookAt(lookAt);
    14.  
    15.         // lets start simple. Collect the Horizontal and Vertical from the keyboard.
    16.         var move = Vector3.zero;
    17.         move.z = Input.GetAxis("Vertical");
    18.         move.x = Input.GetAxis("Horizontal");
    19.         // now transform this into the direction based on the capsule
    20.         move = transform.TransformDirection(move);
    21.         // get and apply this to the controller using Simple Move.
    22.         var controller = GetComponent<CharacterController>();
    23.         controller.SimpleMove(move);
    24.     }
    25.  
    OK, now that we have some movement, lets give it some speed...
    Code (csharp):
    1.  
    2.     // lets define speed as a global public variable
    3.     public float speed = 8;
    4.  
    5.     // lets now update the Update to handle this.
    6.     void Update()
    7.     {
    8.         x -= Input.GetAxis("Mouse Y") * 20;
    9.         y += Input.GetAxis("Mouse X") * 20;
    10.  
    11.         x = ClampAngle(x, -60, 60);
    12.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    13.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    14.  
    15.         var lookAt = camera.transform.TransformPoint(Vector3.forward);
    16.         lookAt.y = transform.position.y;
    17.         transform.LookAt(lookAt);
    18.  
    19.         var move = Vector3.zero;
    20.         move.z = Input.GetAxis("Vertical");
    21.         move.x = Input.GetAxis("Horizontal");
    22.  
    23.         // now first, we need to make sure we use something to clamp the movement.
    24.         // if we press vertical and horizontal at the same time, the movement is faster than if
    25.         // we just pressed either by themselves.
    26.         // we need to limit this.
    27.         if (move.sqrMagnitude > 1) move.Normalize();
    28.  
    29.         // now, we make the move speed based on our variable that we added.
    30.         move *= speed;
    31.  
    32.         move = transform.TransformDirection(move);
    33.         var controller = GetComponent<CharacterController>();
    34.         controller.SimpleMove(move);
    35.     }
    36.  
    OK, now lets look at the third person aspect of this. A third person camera is the exact same camera as a first person camera, its just that we move the camera back so that we see the capsule from a distance.

    Lets see how this works.
    Code (csharp):
    1.  
    2.     // these are the minimum and maximum for third person distances.
    3.     public float minThirdPersonDistance = 0;
    4.     public float maxThirdPersonDistance = 20;
    5.     float thirdPersonDistance = 0;
    6.  
    7.  
    8.     void Update()
    9.     {
    10.         x -= Input.GetAxis("Mouse Y") * 20;
    11.         y += Input.GetAxis("Mouse X") * 20;
    12.  
    13.         x = ClampAngle(x, -60, 60);
    14.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    15.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    16.  
    17.         var lookAt = camera.transform.TransformPoint(Vector3.forward);
    18.         lookAt.y = transform.position.y;
    19.         transform.LookAt(lookAt);
    20.  
    21.         var move = Vector3.zero;
    22.         move.z = Input.GetAxis("Vertical");
    23.         move.x = Input.GetAxis("Horizontal");
    24.         if (move.sqrMagnitude > 1) move.Normalize();
    25.         move *= speed;
    26.         move = transform.TransformDirection(move);
    27.         var controller = GetComponent<CharacterController>();
    28.         controller.SimpleMove(move);
    29.  
    30.         // specfically, we put this code after the positioning of the camera
    31.         // so that we dont affect the position or look rotation of the capsule.
    32.         // lets get the mousewheel.
    33.         // 20 is the sensitivity of the mouse scroll wheel
    34.         thirdPersonDistance -= Input.GetAxis("Mouse ScrollWheel") * 20;
    35.         // now, we clamp the distance to the min and max
    36.         thirdPersonDistance = Mathf.Clamp(thirdPersonDistance, minThirdPersonDistance, maxThirdPersonDistance);
    37.         // now, we move the camera back to where it should be.
    38.         camera.transform.Translate(-Vector3.forward * thirdPersonDistance, Space.Self);
    39.     }
    40.  
    OK, so that is the basics. Below is all the code in one shot.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [RequireComponent(typeof(CharacterController))]
    6. public class SimpleController : MonoBehaviour
    7. {
    8.     Camera camera; // the camera....
    9.     float x, y; // handles mouse capture
    10.     public float speed = 8; // for movement
    11.     // for scrolling....
    12.     public float minThirdPersonDistance = 0;
    13.     public float maxThirdPersonDistance = 20;
    14.     float thirdPersonDistance = 0;
    15.  
    16.  
    17.     // Use this for initialization
    18.     void Start()
    19.     {
    20.         // set the camera up
    21.         camera = Camera.main;
    22.         if (camera == null) camera = Camera.allCameras[0];
    23.  
    24.         // capture the camera's current euler angle.
    25.         var euler = camera.transform.eulerAngles;
    26.         x = euler.x;
    27.         y = euler.y;
    28.     }
    29.  
    30.     void Update()
    31.     {
    32.         // capture the mouse for the view
    33.         x -= Input.GetAxis("Mouse Y") * 20;
    34.         y += Input.GetAxis("Mouse X") * 20;
    35.  
    36.         // clamp the X angle so that we dont look upside down.
    37.         x = ClampAngle(x, -60, 60);
    38.         camera.transform.position = transform.position + Vector3.up * 0.5f;
    39.         camera.transform.eulerAngles = new Vector3(x, y, 0);
    40.  
    41.         // keep the camera looking at the mouse based angles
    42.         var lookAt = camera.transform.TransformPoint(Vector3.forward);
    43.         lookAt.y = transform.position.y;
    44.         transform.LookAt(lookAt);
    45.  
    46.         // handle movement
    47.         var move = Vector3.zero;
    48.         move.z = Input.GetAxis("Vertical");
    49.         move.x = Input.GetAxis("Horizontal");
    50.         if (move.sqrMagnitude > 1) move.Normalize();
    51.         move *= speed;
    52.         move = transform.TransformDirection(move);
    53.         var controller = GetComponent<CharacterController>();
    54.         controller.SimpleMove(move);
    55.  
    56.         // handle the third person camera
    57.         thirdPersonDistance -= Input.GetAxis("Mouse ScrollWheel") * 20;
    58.         thirdPersonDistance = Mathf.Clamp(thirdPersonDistance, minThirdPersonDistance, maxThirdPersonDistance);
    59.         camera.transform.Translate(-Vector3.forward * thirdPersonDistance, Space.Self);
    60.     }
    61.  
    62.     // clamp the current angle
    63.     float ClampAngle(float angle, float min, float max) {
    64.         angle %= 360;
    65.         if (angle > 180) angle -= 360;
    66.         return Mathf.Clamp(angle, min, max);
    67.     }
    68. }
    69.