Advertisement
Guest User

Untitled

a guest
Mar 27th, 2015
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.82 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4.  
  5. public class TPSCamera : MonoBehaviour
  6. {
  7. public Collider target;
  8. // The object we're looking at
  9. new public Camera camera;
  10. // The camera to control
  11. public LayerMask obstacleLayers = -1, groundLayers = -1;
  12. // Which layers should count as obstructing the view? And which are designated ground?
  13. // NOTICE: Make sure that the target collider is not in any of these layers!
  14. public float groundedCheckOffset = 0.7f;
  15. // Tweak so check starts from just within target footing
  16. public float rotationUpdateSpeed = 60.0f,
  17. lookUpSpeed = 20.0f,
  18. distanceUpdateSpeed = 10.0f,
  19. followUpdateSpeed = 10.0f;
  20. // Tweak these to adjust camera responsiveness
  21. public float maxForwardAngle = 80.0f;
  22. // Tweak to adjust camera clamping angle - specifies the maximum angle between target and clamped camera forward
  23. public float minDistance = 0.1f,
  24. maxDistance = 10.0f,
  25. zoomSpeed = 1.0f;
  26. // Tweak to adjust scrollwheel zoom
  27. public bool
  28. showGizmos = true,
  29. // Turn this off to reduce gizmo clutter if needed
  30. requireLock = true,
  31. // Turn this off if the camera should be controllable even without cursor lock
  32. controlLock = true;
  33. // Turn this off if you want mouse lock controlled elsewhere
  34.  
  35.  
  36. private const float movementThreshold = 0.1f, rotationThreshold = 0.1f;
  37. // Tweak these to adjust camera responsiveness
  38. private const float groundedDistance = 0.5f;
  39. // Tweak if the camera goes into ground mode too soon or late
  40.  
  41.  
  42. private Vector3 lastStationaryPosition;
  43. private float optimalDistance, targetDistance;
  44. private bool grounded = false;
  45.  
  46.  
  47. void Reset()
  48. // Run setup on component attach, so it is visually more clear which references are used
  49. {
  50. Setup();
  51.  
  52. }
  53.  
  54.  
  55. void Setup()
  56. // If target and/or camera is not set, try using fallbacks
  57. {
  58. if (target == null)
  59. {
  60. target = GetComponent<Collider>();
  61. }
  62.  
  63. if (camera == null)
  64. {
  65. if (Camera.main != null)
  66. {
  67. camera = Camera.main;
  68. }
  69. }
  70. }
  71.  
  72.  
  73. void Start()
  74. // Verify setup, initialise bookkeeping
  75. {
  76. Setup();
  77. // Retry setup if references were cleared post-add
  78.  
  79. if (target == null)
  80. {
  81. Debug.LogError("No target assigned. Please correct and restart.");
  82. enabled = false;
  83. return;
  84. }
  85.  
  86. if (camera == null)
  87. {
  88. Debug.LogError("No camera assigned. Please correct and restart.");
  89. enabled = false;
  90. return;
  91. }
  92.  
  93. lastStationaryPosition = target.transform.position;
  94. targetDistance = optimalDistance = (camera.transform.position - target.transform.position).magnitude;
  95. }
  96.  
  97.  
  98. float ViewRadius
  99. // The minimum clear radius between the camera and the target
  100. {
  101. get
  102. {
  103. float fieldOfViewRadius = (optimalDistance / Mathf.Sin(90.0f - camera.fieldOfView / 2.0f)) * Mathf.Sin(camera.fieldOfView / 2.0f);
  104. // Half the width of the field of view of the camera at the position of the target
  105. float doubleCharacterRadius = Mathf.Max(target.bounds.extents.x, target.bounds.extents.z) * 2.0f;
  106.  
  107. return Mathf.Min(doubleCharacterRadius, fieldOfViewRadius);
  108. }
  109. }
  110.  
  111.  
  112. Vector3 SnappedCameraForward
  113. // The camera forward vector, clamped to the target forward vector so only horizontal rotation is kept
  114. {
  115. get
  116. {
  117. Vector2 planeForward = new Vector2(camera.transform.forward.x, camera.transform.forward.z);
  118. planeForward = new Vector2(target.transform.forward.x, target.transform.forward.z).normalized *
  119. planeForward.magnitude;
  120. return new Vector3(planeForward.x, camera.transform.forward.y, planeForward.y);
  121. }
  122. }
  123.  
  124.  
  125. void FixedUpdate()
  126. // See if the camera touches the ground and adjust the camera distance if an object blocks the view
  127. {
  128. grounded = Physics.Raycast(
  129. camera.transform.position + target.transform.up * -groundedCheckOffset,
  130. target.transform.up * -1,
  131. groundedDistance,
  132. groundLayers
  133. );
  134. // Shoot a ray downward to see if we're touching the ground
  135.  
  136. Vector3 inverseLineOfSight = camera.transform.position - target.transform.position;
  137.  
  138. RaycastHit hit;
  139. if (Physics.SphereCast(target.transform.position, ViewRadius, inverseLineOfSight, out hit, optimalDistance, obstacleLayers))
  140. // Cast a sphere from the target towards the camera - using the view radius - checking against the obstacle layers
  141. {
  142. targetDistance = Mathf.Min((hit.point - target.transform.position).magnitude, optimalDistance);
  143. // If something is hit, set the target distance to the hit position
  144. }
  145. else
  146. {
  147. targetDistance = optimalDistance;
  148. // If nothing is hit, target the optimal distance
  149. }
  150. }
  151.  
  152.  
  153. void Update()
  154. // Update optimal distance based on scroll wheel input
  155. {
  156. optimalDistance = Mathf.Clamp(
  157. optimalDistance + Input.GetAxis("Mouse ScrollWheel") * -zoomSpeed * Time.deltaTime,
  158. minDistance,
  159. maxDistance
  160. );
  161. }
  162.  
  163.  
  164. void LateUpdate()
  165. // Update camera position - specifics are delegated to camera mode functions
  166. {
  167. // FollowUpdate();
  168. FreeUpdate();
  169. lastStationaryPosition = target.transform.position;
  170.  
  171. DistanceUpdate();
  172. }
  173.  
  174.  
  175. void FollowUpdate()
  176. // Have the camera follow behind the character
  177. {
  178. Vector3 cameraForward = target.transform.position - camera.transform.position;
  179. cameraForward = new Vector3(cameraForward.x, 0.0f, cameraForward.z);
  180. // Ignore camera elevation when calculating the angle
  181.  
  182. float rotationAmount = Vector3.Angle(cameraForward, target.transform.forward);
  183.  
  184. if (rotationAmount < rotationThreshold)
  185. // Stop rotating if we're within the threshold
  186. {
  187. lastStationaryPosition = target.transform.position;
  188. }
  189.  
  190. rotationAmount *= followUpdateSpeed * Time.deltaTime;
  191.  
  192. if (Vector3.Angle(cameraForward, target.transform.right) < Vector3.Angle(cameraForward, target.transform.right * -1.0f))
  193. // Rotate to the left if the camera is to the right of target forward
  194. {
  195. rotationAmount *= -1.0f;
  196. }
  197.  
  198. camera.transform.RotateAround(target.transform.position, Vector3.up, rotationAmount);
  199. }
  200.  
  201.  
  202. void FreeUpdate()
  203. // Control the camera via the mouse
  204. {
  205. float rotationAmount;
  206.  
  207. // Horizontal rotation:
  208. rotationAmount = Input.GetAxis("Mouse X") * rotationUpdateSpeed * Time.deltaTime;
  209. camera.transform.RotateAround(target.transform.position, Vector3.up, rotationAmount);
  210.  
  211. // Vertical rotation:
  212.  
  213. rotationAmount = Input.GetAxis("Mouse Y") * -1.0f * lookUpSpeed * Time.deltaTime;
  214. // Calculate vertical rotation
  215.  
  216. bool lookFromBelow = Vector3.Angle(camera.transform.forward, target.transform.up * -1) >
  217. Vector3.Angle(camera.transform.forward, target.transform.up);
  218.  
  219. camera.transform.RotateAround(target.transform.position, camera.transform.right, rotationAmount);
  220. camera.transform.LookAt(target.transform.position);
  221. // Apply rotation and keep looking at the target
  222.  
  223. float forwardAngle = Vector3.Angle(target.transform.forward, SnappedCameraForward);
  224. // Get the new rotation relative to the target forward vector
  225.  
  226. if (forwardAngle > maxForwardAngle)
  227. // If the new rotation brought the camera over the clamp max, rotate it back by the difference
  228. {
  229. camera.transform.RotateAround(
  230. target.transform.position,
  231. camera.transform.right,
  232. lookFromBelow ? forwardAngle - maxForwardAngle : maxForwardAngle - forwardAngle
  233. );
  234. }
  235.  
  236. }
  237.  
  238.  
  239. void DistanceUpdate()
  240. // Apply any change in camera distance
  241. {
  242. Vector3 targetPosition = target.transform.position + (camera.transform.position - target.transform.position).normalized * targetDistance;
  243. camera.transform.position = Vector3.Lerp(camera.transform.position, targetPosition, 1);
  244.  
  245. //camera.transform.position = new Vector3(camera.transform.position.x, target.transform.position.y, camera.transform.position.z);
  246.  
  247. }
  248.  
  249.  
  250. void OnDrawGizmosSelected()
  251. // Use gizmos to gain information about the state of your setup
  252. {
  253. if (!showGizmos || target == null || camera == null)
  254. {
  255. return;
  256. }
  257.  
  258. Gizmos.color = Color.green;
  259. Gizmos.DrawLine(target.transform.position, target.transform.position + target.transform.forward);
  260. // Visualise the target forward vector
  261.  
  262. Gizmos.color = grounded ? Color.blue : Color.red;
  263. Gizmos.DrawLine(camera.transform.position + target.transform.up * -groundedCheckOffset,
  264. camera.transform.position + target.transform.up * -(groundedCheckOffset + groundedDistance));
  265. // Visualise the camera grounded check and whether or not it is grounded
  266.  
  267. Gizmos.color = Color.green;
  268. Gizmos.DrawLine(camera.transform.position, camera.transform.position + camera.transform.forward);
  269. Gizmos.color = Color.blue;
  270. Gizmos.DrawLine(camera.transform.position, camera.transform.position + SnappedCameraForward);
  271. // Visualise the camera forward vector (green) vs. the SnappedCameraForward
  272. }
  273. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement