目录结构:
实现代码:
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[SerializeField]
private Transform m_tCamera; //相机transform
[SerializeField]
private Transform m_tCameraRoot; //相机旋转中心transform
[SerializeField]
private Transform m_tHead; //相机lookat的头部transform
private const float m_fDefaultDistance = 2.0f; //相机默认与中心点的距离
private const float m_fMinDistance = 1.995f; //相机与中心点的最小距离,在游戏中相机可能离中心点越来越近,设置一个最小值防止贴到人物头上去
void Start()
{
m_vCameraLastPosition = m_tCamera.localPosition;
}
// Update is called once per frame
void LateUpdate()
{
CameraUpdate();
}
private Ray m_CameraRay; //相机发出的射线
private RaycastHit m_CameraRaycastHit; //相机射线射到的点
private Vector3 m_vCameraLastPosition; //相机上次在的位置,如果相机入墙了就恢复到上次的位置
private Vector3 m_vCameraDir; //相机之于中心的单位方向
private void CameraUpdate()
{
m_tCamera.LookAt(m_tHead);
m_CameraRay = new Ray(m_tCamera.position, m_tCamera.forward * (m_fDefaultDistance + 0.5f));
if (Input.GetAxis("Mouse X") != 0) //鼠标移动相机围绕相机中心点旋转
{
m_tCamera.RotateAround(m_tCameraRoot.position, new Vector3(0, 1, 0), Input.GetAxis("Mouse X"));
}
if (Input.GetAxis("Mouse Y") != 0)
{
m_tCamera.RotateAround(m_tCameraRoot.position, new Vector3(1, 0, 0), -Input.GetAxis("Mouse Y"));
}
if(Physics.Raycast(m_CameraRay, out m_CameraRaycastHit, m_fDefaultDistance + 0.5f))
{
if(m_CameraRaycastHit.collider.CompareTag("Player")) //如果相机射线射到的点不是Player
{
m_vCameraLastPosition = m_tCamera.localPosition; //记录相机现在的位置为上一次的点
if (Vector3.Distance(m_tCameraRoot.position, m_tCamera.position) < m_fMinDistance) //如果相机和中心的距离小于最小距离了,lerp到安全距离
{
m_vCameraDir = m_tCamera.localPosition.normalized;
m_tCamera.localPosition = Vector3.Lerp(m_tCamera.localPosition, m_fDefaultDistance * m_vCameraDir, 0.3f);
}
}
else //如果相机射线射到的点不是Player,说明入墙了,lerp回上次记录的点
{
m_tCamera.localPosition = Vector3.Lerp(m_tCamera.localPosition, m_vCameraLastPosition, 0.3f);
}
}
}
}
游戏效果: