daily pastebin goal
85%
SHARE
TWEET

Unity3D's default ThirdPersonCamera in C#

mvaganov Jun 16th, 2013 49 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class ThirdPersonCameraCS : MonoBehaviour {
  5.         public Transform cameraTransform;
  6.         private Transform _target;
  7.  
  8.         // The distance in the x-z plane to the target
  9.         public float distance = 7.0f;
  10.         // the height we want the camera to be above the target
  11.         public float height = 3.0f;
  12.  
  13.         public float angularSmoothLag = 0.3f;
  14.         public float angularMaxSpeed = 15.0f;
  15.         public float heightSmoothLag = 0.3f;
  16.         public float snapSmoothLag = 0.2f;
  17.         public float snapMaxSpeed = 720.0f;
  18.  
  19.         public float clampHeadPositionScreenSpace = 0.75f;
  20.         public float lockCameraTimeout = 0.2f;
  21.                
  22.         private Vector3 headOffset = Vector3.zero;
  23.         private Vector3 centerOffset = Vector3.zero;
  24.        
  25.         private float heightVelocity = 0.0f;
  26.         private float angleVelocity = 0.0f;
  27.         private bool snap = false;
  28.         private ThirdPersonControllerCS controller;
  29.         private float targetHeight = 100000.0f;
  30.        
  31.         public bool canUseMouseLook = true;
  32.         public float sensitivityX = 15;
  33.         public float sensitivityY = 15;
  34.         public float minimumY = -89;
  35.         public float maximumY = 89;
  36.         private float mouseLookAngleOffsetX = 0;
  37.         private float mouseLookAngleOffsetY = 0;
  38.        
  39.         void Awake ()
  40.         {
  41.                 if(!cameraTransform && Camera.main)
  42.                         cameraTransform = Camera.main.transform;
  43.                 if(!cameraTransform) {
  44.                         Debug.Log("Please assign a camera to the ThirdPersonCamera script.");
  45.                         enabled = false;       
  46.                 }
  47.                 _target = transform;
  48.                 if (_target)
  49.                 {
  50.                         controller = _target.GetComponent<ThirdPersonControllerCS>();
  51.                 }
  52.                 if (controller)
  53.                 {
  54.                         CharacterController characterController = (CharacterController)_target.collider;
  55.                         centerOffset = characterController.bounds.center - _target.position;
  56.                         headOffset = centerOffset;
  57.                         headOffset.y = characterController.bounds.max.y - _target.position.y;
  58.                 }
  59.                 else
  60.                         Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached.");
  61.                 Cut(_target, centerOffset);
  62.         }
  63.  
  64.         void DebugDrawStuff ()
  65.         {
  66.                 Debug.DrawLine(_target.position, _target.position + headOffset);
  67.         }
  68.  
  69.         float AngleDistance (float a, float b)
  70.         {
  71.                 a = Mathf.Repeat(a, 360);
  72.                 b = Mathf.Repeat(b, 360);
  73.                 return Mathf.Abs(b - a);
  74.         }
  75.        
  76.         void Apply (Transform dummyTarget, Vector3 dummyCenter)
  77.         {
  78.                 // Early out if we don't have a target
  79.                 if (!controller)
  80.                         return;
  81.                 Vector3 targetCenter = _target.position + centerOffset;
  82.                 Vector3 targetHead = _target.position + headOffset;
  83.        
  84.         //      DebugDrawStuff();
  85.        
  86.                 // Calculate the current & target rotation angles
  87.                 float originalTargetAngle = _target.eulerAngles.y;
  88.                 float currentAngle = cameraTransform.eulerAngles.y;
  89.        
  90.                 // Adjust real target angle when camera is locked
  91.                 float targetAngle = originalTargetAngle;
  92.                
  93.                 // When pressing Fire2 (alt) the camera will snap to the target direction real quick.
  94.                 // It will stop snapping when it reaches the target
  95.                 if (Input.GetButton("Fire2"))
  96.                 {
  97.                         snap = true;
  98.                         if(canUseMouseLook)
  99.                         {
  100.                                 mouseLookAngleOffsetX += Input.GetAxis("Mouse X") * sensitivityX;
  101.                                 mouseLookAngleOffsetY += Input.GetAxis("Mouse Y") * sensitivityY;
  102.                                 Mathf.Repeat(mouseLookAngleOffsetX, 360);
  103.                                 mouseLookAngleOffsetY = Mathf.Clamp(mouseLookAngleOffsetY, minimumY, maximumY);
  104.                         }
  105.                 }
  106.                 else if(Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
  107.                 {
  108.                         mouseLookAngleOffsetX = 0;
  109.                         mouseLookAngleOffsetY = 0;
  110.                 }
  111.                 targetAngle += mouseLookAngleOffsetX;
  112.                
  113.                 if (snap)
  114.                 {
  115.                         // We are close to the target, so we can stop snapping now!
  116.                         if (AngleDistance (currentAngle, originalTargetAngle) < 3.0)
  117.                                 snap = false;
  118.                         currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed);
  119.                 }
  120.                 // Normal camera motion
  121.                 else
  122.                 {
  123.                         if (controller.GetLockCameraTimer () < lockCameraTimeout)
  124.                         {
  125.                                 targetAngle = currentAngle;
  126.                         }
  127.                         // Lock the camera when moving backwards!
  128.                         // * It is really confusing to do 180 degree spins when turning around.
  129.                         if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ())
  130.                                 targetAngle += 180;
  131.                         currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed);
  132.                 }
  133.                 // When jumping don't move camera upwards but only down!
  134.                 if (controller.IsJumping ())
  135.                 {
  136.                         // We'd be moving the camera upwards, do that only if it's really high
  137.                         float newTargetHeight = targetCenter.y + height;
  138.                         if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
  139.                                 targetHeight = targetCenter.y + height;
  140.                 }
  141.                 // When walking always update the target height
  142.                 else
  143.                 {
  144.                         targetHeight = targetCenter.y + height;
  145.                 }
  146.        
  147.                 // Damp the height
  148.                 float currentHeight = cameraTransform.position.y;
  149.                 currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, ref heightVelocity, heightSmoothLag);
  150.        
  151.                 // Convert the angle into a rotation, by which we then reposition the camera
  152.                 Quaternion currentRotation = Quaternion.Euler (0, currentAngle, 0);
  153.                
  154.                 // Set the position of the camera on the x-z plane to:
  155.                 // distance meters behind the target
  156.                 cameraTransform.position = targetCenter;
  157.                 cameraTransform.position += currentRotation * Vector3.back * distance;
  158.        
  159.                 // Set the height of the camera
  160.                 Vector3 temp = cameraTransform.position;
  161.                 temp.y = currentHeight;
  162.                 cameraTransform.position = temp;
  163.                
  164.                 // Always look at the target   
  165.                 SetUpRotation(targetCenter, targetHead);
  166.         }
  167.        
  168.         void LateUpdate () {
  169.                 Apply (transform, Vector3.zero);
  170.         }
  171.        
  172.         void Cut (Transform dummyTarget, Vector3 dummyCenter)
  173.         {
  174.                 var oldHeightSmooth = heightSmoothLag;
  175.                 var oldSnapMaxSpeed = snapMaxSpeed;
  176.                 var oldSnapSmooth = snapSmoothLag;
  177.                
  178.                 snapMaxSpeed = 10000f;
  179.                 snapSmoothLag = 0.001f;
  180.                 heightSmoothLag = 0.001f;
  181.                
  182.                 snap = true;
  183.                 Apply (transform, Vector3.zero);
  184.                
  185.                 heightSmoothLag = oldHeightSmooth;
  186.                 snapMaxSpeed = oldSnapMaxSpeed;
  187.                 snapSmoothLag = oldSnapSmooth;
  188.         }
  189.  
  190.         void SetUpRotation (Vector3 centerPos, Vector3 headPos)
  191.         {
  192.                 // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.
  193.                 // * When jumping up and down we don't want to center the guy in screen space.
  194.                 //  This is important to give a feel for how high you jump and avoiding large camera movements.
  195.                 //  
  196.                 // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
  197.                 //
  198.                 // So here is what we will do:
  199.                 //
  200.                 // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
  201.                 // 2. When grounded we make him be centered
  202.                 // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
  203.                 // 4. When landing we smoothly interpolate towards centering him on screen
  204.                 Vector3 cameraPos = cameraTransform.position;
  205.                 Vector3 offsetToCenter = centerPos - cameraPos;
  206.                
  207.                 // Generate base rotation only around y-axis
  208.                 Quaternion yRotation = Quaternion.LookRotation(new Vector3(offsetToCenter.x, 0, offsetToCenter.z));
  209.        
  210.                 Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
  211.                 cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset);
  212.        
  213.                 // Calculate the projected center position and top position in world space
  214.                 Ray centerRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 1));
  215.                 Ray topRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, clampHeadPositionScreenSpace, 1));
  216.        
  217.                 Vector3 centerRayPos = centerRay.GetPoint(distance);
  218.                 Vector3 topRayPos = topRay.GetPoint(distance);
  219.                
  220.                 float centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction);
  221.                
  222.                 float heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y);
  223.        
  224.                 float extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y);
  225.                 if (extraLookAngle < centerToTopAngle)
  226.                 {
  227.                         extraLookAngle = 0;
  228.                 }
  229.                 else
  230.                 {
  231.                         extraLookAngle = extraLookAngle - centerToTopAngle;
  232.                         cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0);
  233.                 }
  234.         }
  235.        
  236.         Vector3 GetCenterOffset ()
  237.         {
  238.                 return centerOffset;
  239.         }
  240. }
RAW Paste Data
Top