二、功能开发阶段-2-相机的控制(版本_V1.0)
前言:
相机的控制是一个比较复杂的过程,尤其是在3D游戏中。Unity的资源商店里有很多摄像机插件,我也使用过。但是因为大部分都封装了代码,看不到里面的内容,那么有时候想修改功能却不是很方便。
这里我将逐步的完成摄像机的控制,这个是初始版本,我会在将来逐步完成相机的功能。
一、摄像机的结构
1.相机的移动
2.相机的旋转
3.相机的缩放
4.真正相机的位置
a.首先创建一个空物体,并且命名为:“CameraFallow”。
b.在CameraFallow物体下,创建空物体,并且命名为:“CameraRotationY”。
c.在CameraRotationY物体下,创建空物体,并且命名为:“CameraRotationX”;
d.在CameraRotationX物体下,创建空物体,并且命名为:“CameraZoom”;
e.在CameraZoom物体下,创建空物体,并且命名为:“CameraContainer”;
f.在CameraContainer物体下,将我们的相机拖到它的下面,作为子物体。其最终结构图如下:
解释:
CameraFallow负责跟随角色
CameraRotationY负责绕Y轴旋转
CameraRotationX负责绕X轴旋转
CameraZoom负责缩放功能
CameraContainer是相机的容器
Main Camera是真正的相机
二、相机的脚本
1.创建代码“CameraCtrl.cs”,并且挂载到CameraFallow上。
2.具体的代码如下:
public class CameraCtrl : MonoSingleton<CameraCtrl>
{
/// <summary>
/// 相机的旋转X轴
/// </summary>
private Transform m_CameraRotationX;
/// <summary>
/// 相机的旋转Y轴
/// </summary>
public Transform CameraRotationY;
/// <summary>
/// 相机的缩放
/// </summary>
private Transform m_CameraZoom;
/// <summary>
/// 相机的容器
/// </summary>
private Transform m_CameraContainer;
/// <summary>
/// 围绕Y的旋转的时候,鼠标X方向的增量
/// </summary>
[SerializeField]
public float m_XSensitivity = 1.0f;
/// <summary>
/// 围绕X轴旋转的时候,鼠标Y轴方向的增量
/// </summary>
[SerializeField]
private float m_YSensitivity = 1.0f;
/// <summary>
/// 是否限制围绕X轴旋转
/// </summary>
[SerializeField]
private bool m_ClampVerticalRotation = true;
/// <summary>
/// X轴旋转的最小值
/// </summary>
[SerializeField]
private float m_MinimumX = -90F;
/// <summary>
/// X轴旋转的最大值
/// </summary>
[SerializeField]
private float m_MaximumX = 90F;
/// <summary>
/// 是否平滑过渡
/// </summary>
[SerializeField]
private bool m_Smooth;
/// <summary>
/// 平滑过渡时间
/// </summary>
[SerializeField]
private float m_SmoothTime = 5.0f;
/// <summary>
/// 相机缩放的速度
/// </summary>
[SerializeField]
private float m_ZoomSpeed = 5.0f;
/// <summary>
/// 相机近距离
/// </summary>
[SerializeField]
private float m_ZoomNear = -2.0f;
/// <summary>
/// 相机最远距离
/// </summary>
[SerializeField]
private float m_ZoomFar = -6.0f;
/// <summary>
/// 相机m_CameraRotationX的本地旋转值
/// </summary>
private Quaternion m_CameraTargetRotX;
/// <summary>
/// 相机m_CameraRotationY的本地旋转值
/// </summary>
private Quaternion m_CameraTargetRotY;
/// <summary>
/// 相机缩放目标位置
/// </summary>
private Vector3 m_CameraTargetZoomPos;
private Transform m_Player;
/// <summary>
/// 相机的高度
/// </summary>
[SerializeField]
private Vector3 m_CameraHight = new Vector3(0.0f, 1.5f, 0.0f);
[SerializeField]
private float m_CameraFollowSpeed = 1.0f;
[SerializeField]
private bool m_UseMouse;
private void Awake()
{
CameraRotationY = transform.Find("CameraRotationY").transform;
m_CameraRotationX = transform.Find("CameraRotationY/CameraRotationX").transform;
m_CameraZoom = transform.Find("CameraRotationY/CameraRotationX/CameraZoom").transform;
m_CameraContainer = transform.Find("CameraRotationY/CameraRotationX/CameraZoom/CameraContainer").transform;
m_CameraTargetRotX = m_CameraRotationX.transform.localRotation;
m_CameraTargetRotY = CameraRotationY.transform.localRotation;
m_Player = GameObject.FindGameObjectWithTag("Player").transform;
}
private void Start()
{
Init();
}
/// <summary>
/// 相机初始化
/// </summary>
public void Init()
{
m_CameraZoom.localPosition = new Vector3(0.0f, 0.0f, m_ZoomNear);
m_UseMouse = false;
Cursor.visible = m_UseMouse;
}
/// <summary>
/// 相机跟随角色
/// </summary>
public void CameraAutoFollowPlayer()
{
transform.position = Vector3.Lerp(transform.position, m_Player.position + m_CameraHight, Time.deltaTime * m_CameraFollowSpeed);
}
/// <summary>
/// 相机实时看着主角
/// </summary>
/// <param name="position"></param>
private void CamaraAutoLookAtPlayer()
{
m_CameraContainer.LookAt(m_Player.position + m_CameraHight);
}
private void LateUpdate()
{
CameraAutoFollowPlayer();
CamaraAutoLookAtPlayer();
CameraZoom();
if (!m_UseMouse)
{
RotateView();
}
if (Input.GetKeyDown(KeyCode.Tab))
{
m_UseMouse = !m_UseMouse;
Cursor.visible = m_UseMouse;
}
}
private void RotateView()
{
float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * m_XSensitivity;
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * m_YSensitivity;
m_CameraTargetRotX *= Quaternion.Euler(-xRot, 0.0f, 0f);
m_CameraTargetRotY *= Quaternion.Euler(0.0f, yRot, 0f);
if (m_ClampVerticalRotation)
{
m_CameraTargetRotX = ClampRotationAroundAxis(m_CameraTargetRotX);
}
if (m_Smooth)
{
m_CameraRotationX.transform.localRotation = Quaternion.Slerp(m_CameraRotationX.transform.localRotation, m_CameraTargetRotX,
m_SmoothTime * Time.deltaTime);
CameraRotationY.transform.localRotation = Quaternion.Slerp(CameraRotationY.transform.localRotation, m_CameraTargetRotY,
m_SmoothTime * Time.deltaTime);
}
else
{
m_CameraRotationX.transform.localRotation = m_CameraTargetRotX;
CameraRotationY.transform.localRotation = m_CameraTargetRotY;
}
}
private void CameraZoom()
{
if (Input.GetAxis("Mouse ScrollWheel") < 0.0f)
{
m_CameraTargetZoomPos = new Vector3(0.0f, 0.0f, m_CameraZoom.localPosition.z - 2.0f);
m_CameraTargetZoomPos = ClampCameraZoom(m_CameraTargetZoomPos);
}
else if (Input.GetAxis("Mouse ScrollWheel") > 0.0f)
{
m_CameraTargetZoomPos = new Vector3(0.0f, 0.0f, m_CameraZoom.localPosition.z + 2.0f);
m_CameraTargetZoomPos = ClampCameraZoom(m_CameraTargetZoomPos);
}
if (m_CameraTargetZoomPos != Vector3.zero)
{
m_CameraZoom.localPosition = Vector3.Lerp(m_CameraZoom.localPosition, m_CameraTargetZoomPos, m_ZoomSpeed * Time.deltaTime);
}
}
/// <summary>
/// 限制缩放摄像机的值
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
private Vector3 ClampCameraZoom(Vector3 pos)
{
float value = Mathf.Clamp(pos.z, m_ZoomFar, m_ZoomNear);
return new Vector3(0, 0, value);
}
/// <summary>
/// 限制X轴的旋转
/// </summary>
/// <param name="q"></param>
/// <returns></returns>
private Quaternion ClampRotationAroundAxis(Quaternion q)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.x);
angleX = Mathf.Clamp(angleX, m_MinimumX, m_MaximumX);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
return q;
}
}
3.我的设置如下图: