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;
}
}