AutoCam.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using UnityEngine;
  3. #if UNITY_EDITOR
  4. #endif
  5. namespace UnityStandardAssets.Cameras
  6. {
  7. [ExecuteInEditMode]
  8. public class AutoCam : PivotBasedCameraRig
  9. {
  10. [SerializeField] private float m_MoveSpeed = 3; // How fast the rig will move to keep up with target's position
  11. [SerializeField] private float m_TurnSpeed = 1; // How fast the rig will turn to keep up with target's rotation
  12. [SerializeField] private float m_RollSpeed = 0.2f;// How fast the rig will roll (around Z axis) to match target's roll.
  13. [SerializeField] private bool m_FollowVelocity = false;// Whether the rig will rotate in the direction of the target's velocity.
  14. [SerializeField] private bool m_FollowTilt = true; // Whether the rig will tilt (around X axis) with the target.
  15. [SerializeField] private float m_SpinTurnLimit = 90;// The threshold beyond which the camera stops following the target's rotation. (used in situations where a car spins out, for example)
  16. [SerializeField] private float m_TargetVelocityLowerLimit = 4f;// the minimum velocity above which the camera turns towards the object's velocity. Below this we use the object's forward direction.
  17. [SerializeField] private float m_SmoothTurnTime = 0.2f; // the smoothing for the camera's rotation
  18. private float m_LastFlatAngle; // The relative angle of the target and the rig from the previous frame.
  19. private float m_CurrentTurnAmount; // How much to turn the camera
  20. private float m_TurnSpeedVelocityChange; // The change in the turn speed velocity
  21. private Vector3 m_RollUp = Vector3.up;// The roll of the camera around the z axis ( generally this will always just be up )
  22. protected override void FollowTarget(float deltaTime)
  23. {
  24. // if no target, or no time passed then we quit early, as there is nothing to do
  25. if (!(deltaTime > 0) || m_Target == null)
  26. {
  27. return;
  28. }
  29. // initialise some vars, we'll be modifying these in a moment
  30. var targetForward = m_Target.forward;
  31. var targetUp = m_Target.up;
  32. if (m_FollowVelocity && Application.isPlaying)
  33. {
  34. // in follow velocity mode, the camera's rotation is aligned towards the object's velocity direction
  35. // but only if the object is traveling faster than a given threshold.
  36. if (targetRigidbody.velocity.magnitude > m_TargetVelocityLowerLimit)
  37. {
  38. // velocity is high enough, so we'll use the target's velocty
  39. targetForward = targetRigidbody.velocity.normalized;
  40. targetUp = Vector3.up;
  41. }
  42. else
  43. {
  44. targetUp = Vector3.up;
  45. }
  46. m_CurrentTurnAmount = Mathf.SmoothDamp(m_CurrentTurnAmount, 1, ref m_TurnSpeedVelocityChange, m_SmoothTurnTime);
  47. }
  48. else
  49. {
  50. // we're in 'follow rotation' mode, where the camera rig's rotation follows the object's rotation.
  51. // This section allows the camera to stop following the target's rotation when the target is spinning too fast.
  52. // eg when a car has been knocked into a spin. The camera will resume following the rotation
  53. // of the target when the target's angular velocity slows below the threshold.
  54. var currentFlatAngle = Mathf.Atan2(targetForward.x, targetForward.z)*Mathf.Rad2Deg;
  55. if (m_SpinTurnLimit > 0)
  56. {
  57. var targetSpinSpeed = Mathf.Abs(Mathf.DeltaAngle(m_LastFlatAngle, currentFlatAngle))/deltaTime;
  58. var desiredTurnAmount = Mathf.InverseLerp(m_SpinTurnLimit, m_SpinTurnLimit*0.75f, targetSpinSpeed);
  59. var turnReactSpeed = (m_CurrentTurnAmount > desiredTurnAmount ? .1f : 1f);
  60. if (Application.isPlaying)
  61. {
  62. m_CurrentTurnAmount = Mathf.SmoothDamp(m_CurrentTurnAmount, desiredTurnAmount,
  63. ref m_TurnSpeedVelocityChange, turnReactSpeed);
  64. }
  65. else
  66. {
  67. // for editor mode, smoothdamp won't work because it uses deltaTime internally
  68. m_CurrentTurnAmount = desiredTurnAmount;
  69. }
  70. }
  71. else
  72. {
  73. m_CurrentTurnAmount = 1;
  74. }
  75. m_LastFlatAngle = currentFlatAngle;
  76. }
  77. // camera position moves towards target position:
  78. transform.position = Vector3.Lerp(transform.position, m_Target.position, deltaTime*m_MoveSpeed);
  79. // camera's rotation is split into two parts, which can have independend speed settings:
  80. // rotating towards the target's forward direction (which encompasses its 'yaw' and 'pitch')
  81. if (!m_FollowTilt)
  82. {
  83. targetForward.y = 0;
  84. if (targetForward.sqrMagnitude < float.Epsilon)
  85. {
  86. targetForward = transform.forward;
  87. }
  88. }
  89. var rollRotation = Quaternion.LookRotation(targetForward, m_RollUp);
  90. // and aligning with the target object's up direction (i.e. its 'roll')
  91. m_RollUp = m_RollSpeed > 0 ? Vector3.Slerp(m_RollUp, targetUp, m_RollSpeed*deltaTime) : Vector3.up;
  92. transform.rotation = Quaternion.Lerp(transform.rotation, rollRotation, m_TurnSpeed*m_CurrentTurnAmount*deltaTime);
  93. }
  94. }
  95. }