前言
这是以前写的人物控制器(包含第一人称、第三人称、漫游视角),这里做个记录,方便后续参考使用.
实现
模型使用官方的,操作使用鼠标右键控制视角,键盘WASD、Shift控制人物移动.
切换到漫游视角(God)时,有BUG,待修复.
人物控制:
/// <summary>
/// 第三人称.人物移动操作.
/// </summary>
private void MoveUpdate_ThirdController()
{
//按住左SHIFT 加速.
if (Input.GetKey(KeyCode.LeftShift))
{
isRun = true;
}
else
{
isRun = false;
}
//按下了 W A S D.
if (v != 0 || h != 0)
{
if (isRun) //执行奔跑动画.
{
m_Animator.SetBool("Run", true);
}
else //执行行走动画.
{
m_Animator.SetBool("Run", false);
m_Animator.SetBool("Walk", true);
}
float rotY = playerCamera.transform.rotation.eulerAngles.y; //摄像机世界坐标前方.
Vector3 dir = new Vector3(h, 0, v); //移动方向.
dir = Quaternion.Euler(0, rotY, 0) * dir; //移动方向的前方为摄像机前方.(按下W,向摄像机正前方行走)(前进方向必须是摄像机的前方)
//m_CC.SimpleMove(dir);
m_CC.Move(dir * walkSpeed_Third); //m_CC为CharacterController组件.
m_Transform.localRotation = Quaternion.LookRotation(dir);
}
else
{
m_Animator.SetBool("Walk", false);
}
}
/// <summary>
/// 第一人称.人物移动操作.
/// </summary>
private void MoveUpdate_FirstController()
{
//按住左SHIFT 加速.
if (Input.GetKey(KeyCode.LeftShift))
{
isRun = true; //加速.
}
else
{
isRun = false; //正常速度.
}
//按下了 W A S D.
if (v != 0 || h != 0)
{
//todo:----->>当前动画默认是移动的.而且没有向后走的动画.所以第一人称不使用动画.
float rotY = playerCamera.transform.rotation.eulerAngles.y; //摄像机世界坐标前方.
Vector3 dir = new Vector3(h, 0, v); //移动方向.
dir = Quaternion.Euler(0, rotY, 0) * dir; //移动方向的前方为摄像机前方.(按下W,向摄像机正前方行走)(前进方向必须是摄像机的前方)
if (isRun) //加速.
{
//m_CC.SimpleMove(dir * runSpeed_First);
m_CC.Move(dir * runSpeed_First); //m_CC为CharacterController组件.
}
else //正常速度.
{
//m_CC.SimpleMove(dir * walkSpeed_First);
m_CC.Move(dir * walkSpeed_First);
}
}
}
/// <summary>
/// 漫游模式.人物移动操作.(不受重力影响,飞行.)
/// </summary>
private void MoveUpdate_GodController()
{
//按住左SHIFT 加速.
if (Input.GetKey(KeyCode.LeftShift))
{
isRun = true; //加速.
}
else
{
isRun = false; //正常速度.
}
//按下了 W A S D.
if (v != 0 || h != 0)
{
float rotY = playerCamera.transform.localRotation.eulerAngles.y; //摄像机自身坐标前方.左右.
float rotX = playerCamera.transform.localRotation.eulerAngles.x; //摄像机自身坐标前方.上下.
Vector3 dir = new Vector3(h, 0, v); //移动方向.
dir = Quaternion.Euler(rotX, rotY, 0) * dir; //移动方向的前方为摄像机前方.(按下W,向摄像机正前方行走)(前进方向必须是摄像机的前方)
if (isRun) //加速.
{
//m_CC.SimpleMove(dir * runSpeed_First);
//m_CC.Move(dir * runSpeed_First);
m_Transform.Translate(dir * runSpeed_God);
}
else //正常速度.
{
//m_CC.SimpleMove(dir * walkSpeed_First);
//m_CC.Move(dir * walkSpeed_First);
m_Transform.Translate(dir * walkSpeed_God);
}
}
}
视角控制:(放在LateUpdate)
//----->>第三人称视角控制.
void Start ()
{
m_Transform = gameObject.GetComponent<Transform>();
//playerPerson = GameObject.Find("Player/Person").GetComponent<Transform>();
playerPerson = GameObject.Find("Player/Person/HeadPos").GetComponent<Transform>(); //最好朝向的是人物的头部.
dir = playerPerson.position - m_Transform.localPosition; //先获取摄像机指向人物的方向向量. //朝向头部时,不能使用playerPerson.localPosition
}
/// <summary>
/// 第三人称 摄像机旋转控制.
/// </summary>
private void CameraController_ThirdController()
{
float x = Input.GetAxis("Mouse X") * rotateSpeed;
float y = Input.GetAxis("Mouse Y") * rotateSpeed;
distance -= (Input.GetAxis("Mouse ScrollWheel") * scrollSpeed);
distance = Mathf.Clamp(distance, minDis, maxDis);
//按住鼠标右键,旋转视角.
if (Input.GetMouseButton(1))
{
Quaternion rotX = Quaternion.Euler(0, x, 0);
//Quaternion rotY = Quaternion.Euler(-y, 0, 0);
//摄像机世界坐标Z 比人物世界坐标Z 远(Z轴在人物前方),上下滑动方向改变.
if (m_Transform.position.z <= playerPerson.position.z) //摄像机在人物后方.
{
#region 限制上下角度范围.(不同点:rotY的Euler是-y)
Quaternion rotY = Quaternion.Euler(-y, 0, 0);
if (m_Transform.localRotation.eulerAngles.x < minAngleX) //当向下角度越界时.
{
if (y < 0) //达到最下,向上滑动.
{
dir = rotX * rotY * dir;
}
else //达到最下,向下滑动. (不再向下滑)
{
dir = rotX * dir;
}
}
else if (m_Transform.localRotation.eulerAngles.x > maxAngleX) //当向上角度越界时.
{
if (y > 0) //达到最上,向下滑动.
{
dir = rotX * rotY * dir;
}
else //达到最上,向上滑动. (不再向上滑)
{
dir = rotX * dir;
}
}
else //上下角度在范围内.
{
dir = rotX * rotY * dir;
}
#endregion
}
else //摄像机在人物前方.
{
#region 限制上下角度范围.(不同点:rotY的Euler是y)
Quaternion rotY = Quaternion.Euler(y, 0, 0);
if (m_Transform.localRotation.eulerAngles.x < minAngleX) //当向下角度越界时.
{
if (y < 0) //达到最下,向上滑动.
{
dir = rotX * rotY * dir;
}
else //达到最下,向下滑动. (不再向下滑)
{
dir = rotX * dir;
}
}
else if (m_Transform.localRotation.eulerAngles.x > maxAngleX) //当向上角度越界时.
{
if (y > 0) //达到最上,向下滑动.
{
dir = rotX * rotY * dir;
}
else //达到最上,向上滑动. (不再向上滑)
{
dir = rotX * dir;
}
}
else //上下角度在范围内.
{
dir = rotX * rotY * dir;
}
#endregion
}
}
m_Transform.localPosition = playerPerson.position - dir.normalized * distance;
m_Transform.LookAt(playerPerson);
}
//----->>第一人称视角控制.
void Start ()
{
m_Transform = gameObject.GetComponent<Transform>();
playerPerson = GameObject.Find("Player/Person").GetComponent<Transform>();
}
void LateUpdate ()
{
float x = Input.GetAxis("Mouse X");
float y = -Input.GetAxis("Mouse Y");
playerPerson.Rotate(Vector3.up, x, Space.Self);
m_Transform.Rotate(Vector3.right, y, Space.Self);
m_Transform.localRotation = ClampRotationAroundXAxis(m_Transform.localRotation);
}
/// <summary>
/// 限制四元数的欧拉角X. (这是官方案例的方法.)
/// </summary>
private Quaternion ClampRotationAroundXAxis(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, minRotX, maxRotX);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
return q;
}
项目链接_Github.
项目链接_csdn.
完毕.