mvaganov

Unity3D's default ThirdPersonCamera in C#

Jun 16th, 2013
72
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×