使用了 Mathf.SmoothDamp() 函数,来实现摄像机的平滑过度。
转载请注明出处:https://www.cnblogs.com/jietian331/p/12626530.html
代码如下:
1 using System; 2 using UnityEngine; 3 using UnityEngine.EventSystems; 4 5 class PlayerCamera : MonoBehaviour 6 { 7 const float 8 MouseSmoothingFactor = 0.1f, 9 MaxDistance = 16, 10 MinDistance = 1f, 11 MinAngleY = -30f, 12 MaxAngleY = 60f; 13 14 [SerializeField] 15 Transform m_target; 16 [SerializeField] 17 float m_distance; 18 [SerializeField] 19 float m_offsetY; 20 21 Camera m_camera; 22 float m_mouseX; 23 float m_mouseY = 30; 24 float m_mouseXSmooth; 25 float m_mouseYSmooth; 26 27 28 #region singleton 29 30 static PlayerCamera s_instance; 31 public static PlayerCamera Singleton 32 { 33 get 34 { 35 if (s_instance == null) 36 { 37 var asset = Resources.Load<PlayerCamera>("Prefabs/Game/PlayerCamera"); 38 s_instance = GameObject.Instantiate(asset); 39 } 40 return s_instance; 41 } 42 } 43 44 #endregion 45 46 47 #region Property 48 49 float Distance 50 { 51 get { return m_distance; } 52 set { m_distance = Mathf.Clamp(value, MinDistance, MaxDistance); } 53 } 54 55 public Camera Camera 56 { 57 get { return m_camera; } 58 } 59 60 public static bool ClickedUI 61 { 62 get { return GUIUtility.hotControl != 0 || (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject()); } 63 } 64 65 public bool Active 66 { 67 set { gameObject.SetActive(value); } 68 } 69 70 #endregion 71 72 73 static float ClampAngle(float angle, float min, float max) 74 { 75 while (angle < -360 || angle > 360) 76 { 77 if (angle < -360) 78 angle += 360; 79 if (angle > 360) 80 angle -= 360; 81 } 82 83 return Mathf.Clamp(angle, min, max); 84 } 85 86 87 void Start() 88 { 89 DontDestroyOnLoad(gameObject); 90 91 // camera 92 m_camera = GetComponent<Camera>(); 93 94 // setting 95 Distance = GameConfig.Instance.CameraDefaltDistance; 96 } 97 98 99 public void SetTarget(Transform target, float height) 100 { 101 if (target == null) 102 throw new ArgumentNullException("target"); 103 104 m_target = target; 105 m_offsetY = height * 0.8f; 106 } 107 108 Vector3 GetSmoothDir() 109 { 110 if (Input.GetKey(KeyCode.Mouse1)) 111 { 112 float mouseXAxis = Input.GetAxis("Mouse X"); 113 float mouseYAxis = Input.GetAxis("Mouse Y"); 114 m_mouseX += mouseXAxis * 6; 115 m_mouseY -= mouseYAxis * 4; 116 } 117 else 118 { 119 bool left = Input.GetKey(KeyCode.Q); 120 bool right = Input.GetKey(KeyCode.E); 121 bool downward = Input.GetKey(KeyCode.Z); 122 bool upward = Input.GetKey(KeyCode.C); 123 bool reset = Input.GetKey(KeyCode.X); 124 125 if (left || right) 126 { 127 float eulerY = left ? -2 : 2; 128 m_mouseX += eulerY; 129 } 130 else if (downward || upward) 131 { 132 float offsetY = downward ? 2f : -2f; 133 m_mouseY -= offsetY; 134 } 135 else if (reset) 136 { 137 m_mouseX = 0; 138 m_mouseY = 30; 139 } 140 } 141 142 float currentVelX = 0, currentVelY = 0; 143 m_mouseXSmooth = Mathf.SmoothDamp(m_mouseXSmooth, m_mouseX, ref currentVelX, MouseSmoothingFactor); 144 m_mouseY = ClampAngle(m_mouseY, MinAngleY, MaxAngleY); 145 m_mouseYSmooth = Mathf.SmoothDamp(m_mouseYSmooth, m_mouseY, ref currentVelY, MouseSmoothingFactor); 146 m_mouseYSmooth = ClampAngle(m_mouseYSmooth, MinAngleY, MaxAngleY); 147 148 // Distance 149 float scrollWheel = Input.GetAxis("Mouse ScrollWheel") * 3; 150 if (scrollWheel != 0) 151 Distance -= scrollWheel; 152 153 Vector3 offset = new Vector3(0, 0, Distance); 154 Quaternion rotation = Quaternion.Euler(m_mouseYSmooth, m_mouseXSmooth, 0); 155 return rotation * offset; 156 } 157 158 // A follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update 159 void LateUpdate() 160 { 161 if (!m_target) 162 return; 163 164 Vector3 dir = GetSmoothDir(); 165 ResetCamera(dir); 166 } 167 168 void ResetCamera(Vector3 forward) 169 { 170 Vector3 center = m_target.position + new Vector3(0, m_offsetY); 171 172 // 摄像机不会被物体遮住,用射线检测 173 RaycastHit hit; 174 Ray ray = new Ray(center, -forward); 175 int groundMask = StaticLayers.Ground.GetLayerMask(); 176 bool raycast = Physics.Raycast(ray, out hit, Distance, groundMask); 177 Vector3 pos; 178 if (raycast) 179 pos = hit.point + forward * 0.05f; 180 else 181 pos = center - forward; 182 183 transform.position = pos; 184 transform.LookAt(center); 185 } 186 }