using UnityEngine; public class PlayerCamera3rd : MonoBehaviour { Vector3 m_defaultDir; Transform m_PlayerTransform; Vector3 m_RotateValue; Vector3 m_PitchRotateAxis; //俯仰方向轴 Vector3 m_YawRotateAxis;//左右横向旋转轴 public float distance = 4; public float speed = 120f; public Vector3 offest = new Vector3(0, 1.5f, 0); public float followRange = 0.5f; Vector3 followPoint; //翻转pitch方向相机旋转 public bool invertPitch; public Vector2 pitchLimit = new Vector2(-40f,85f); //修改相机位置缓动 float m_CurrentDistance; float m_DistanceRecoveryDelayCounter; public float distanceRecoverySpeed = 4f; public float distanceRecoveryDelay = 0.3f; public Transform followPlayer; Vector3 upAxis; void OnEnable() { if (followPlayer == null) { m_PlayerTransform = GameObject.FindGameObjectWithTag("Player").transform; } else m_PlayerTransform = followPlayer; followPoint = m_PlayerTransform.position; upAxis = -Physics.gravity.normalized; m_defaultDir = Vector3.ProjectOnPlane((transform.position - m_PlayerTransform.position), upAxis).normalized; m_YawRotateAxis = upAxis; } void LateUpdate() { Vector2 inputDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")); m_RotateValue.x += inputDelta.x * speed * Time.smoothDeltaTime; m_RotateValue.x = AngleCorrection(m_RotateValue.x); m_RotateValue.y += inputDelta.y * speed * (invertPitch ? -1 : 1) * Time.smoothDeltaTime; m_RotateValue.y = AngleCorrection(m_RotateValue.y); m_RotateValue.y = Mathf.Clamp(m_RotateValue.y, pitchLimit.x, pitchLimit.y); var horizontalQuat = Quaternion.AngleAxis(m_RotateValue.x, m_YawRotateAxis); m_PitchRotateAxis = Vector3.Cross(upAxis, Vector3.ProjectOnPlane(transform.forward, upAxis)); var verticalQuat = Quaternion.AngleAxis(m_RotateValue.y, m_PitchRotateAxis); var finalDir = horizontalQuat * verticalQuat * m_defaultDir; var from = m_PlayerTransform.localToWorldMatrix.MultiplyPoint3x4(offest); var to = from + finalDir * distance; var exceptTo = ObstacleProcess(from, to); var expectDistance = Vector3.Distance(exceptTo, from); followPoint= UpdateFocusPoint(m_PlayerTransform,followRange); m_CurrentDistance = (followPoint - transform.position).magnitude; //Debug.Log(m_CurrentDistance); if (expectDistance < m_CurrentDistance) { m_CurrentDistance = expectDistance; m_DistanceRecoveryDelayCounter = distanceRecoveryDelay; } else { if (m_DistanceRecoveryDelayCounter > 0f) m_DistanceRecoveryDelayCounter -= Time.deltaTime; else { m_CurrentDistance = Mathf.Lerp(m_CurrentDistance, expectDistance, Time.smoothDeltaTime * distanceRecoverySpeed); } } transform.position = Vector3.Slerp(transform.position,from + finalDir * m_CurrentDistance,Time.deltaTime* distanceRecoverySpeed); transform.LookAt(from); } /// <summary> /// 更新相机跟随点位置 /// </summary> /// <param name="m_PlayerTransform"></param> /// <param name="followRange"></param> /// <returns></returns> Vector3 UpdateFocusPoint(Transform m_PlayerTransform,float followRange) { Vector3 followPoint = m_PlayerTransform.position; if (followRange>0) { if ((m_PlayerTransform.position - followPoint).magnitude > followRange) { followPoint = Vector3.Slerp(followPoint, m_PlayerTransform.position, Time.deltaTime * distanceRecoverySpeed); } } else { followPoint = m_PlayerTransform.position; } return followPoint; } float AngleCorrection(float value) { if (value > 180f) return m_RotateValue.x - 360f; else if (value < -180f) return m_RotateValue.x + 360f; return value; } public LayerMask obstacleLayerMask; public float obstacleSphereRadius = 0.3f; Vector3 ObstacleProcess(Vector3 from,Vector3 to) { var dir = (to - from).normalized; var hit = default(RaycastHit); var isHit = Physics.SphereCast(new Ray(from, dir), obstacleSphereRadius, out hit, distance, obstacleLayerMask); if (isHit) { return hit.point + (-dir * obstacleSphereRadius); } return to; } }