前言:这个阶段准备写一个角色状态机,而在写角色状态机的时候,我准备从最简单的操作物体的移动旋转开始。紧接着梳理一下层、Tag和碰撞的知识点,进而再实现角色状态机。
实现简单的角色控制:
一、使角色始终紧贴地面。。
二、点击鼠标左键,获取目标位置。
三、控制角色移动和有过渡动画的转向。
详细步骤如下:
1.首先我们在角色绑定上脚本:
2.定义属性:
/// <summary>
/// 角色移动速度
/// </summary>
[SerializeField]
private float m_Speed = 10.0f;
/// <summary>
/// 角色移动目标位置
/// </summary>
private Vector3 m_TargetPos = Vector3.zero;
/// <summary>
/// 角色转向(四元数)
/// </summary>
private Quaternion m_DirectionQua;
/// <summary>
/// 角色转向速度
/// </summary>
private float m_RotationSpeed = 0.0f;
/// <summary>
/// 角色完成转向
/// </summary>
private bool m_RotationOver = false;
/// <summary>
/// 角色控制器
/// </summary>
private CharacterController m_CharacterController;
3.使角色紧贴地面并且获得目标位置(以下代码片段写在Update里面):
//1.让角色始终贴紧地面
if (!m_CharacterController.isGrounded)
{
m_CharacterController.Move((transform.position + new Vector3(0.0f, -1000.0f, 0.0f)) - transform.position);
}
//2.点击鼠标左键 获得目标位置
if (Input.GetMouseButtonUp(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.collider.gameObject.name.Equals("Ground", System.StringComparison.CurrentCultureIgnoreCase))
{
m_TargetPos = hitInfo.point;
m_RotationOver = false;
m_RotationSpeed = 0.0f;
}
}
}
4.使角色转向和移动(同样写在Update里面):
//3.根据目标位置和当前位置判断 是否应该移动和转向
if (m_TargetPos != Vector3.zero)
{
if (Vector3.Distance(m_TargetPos, transform.position) > 0.1f)
{
Vector3 direction = m_TargetPos - transform.position;
direction = direction.normalized;
direction.y = 0.0f;
//1.转向
if (!m_RotationOver)
{
m_RotationSpeed += 5.0f;
m_DirectionQua = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Lerp(transform.rotation, m_DirectionQua, m_RotationSpeed * Time.deltaTime);
if (Quaternion.Angle(transform.rotation, m_DirectionQua) < 0.1f)
{
m_RotationOver = true;
m_RotationSpeed = 1.0f;
}
}
//2.移动
m_CharacterController.Move(direction * m_Speed * Time.deltaTime);
}
}
5.完整的代码如下:
public class RoleCtrl_Study : MonoBehaviour
{
/// <summary>
/// 角色移动速度
/// </summary>
[SerializeField]
private float m_Speed = 10.0f;
/// <summary>
/// 角色移动目标位置
/// </summary>
private Vector3 m_TargetPos = Vector3.zero;
/// <summary>
/// 角色转向(四元数)
/// </summary>
private Quaternion m_DirectionQua;
/// <summary>
/// 角色转向速度
/// </summary>
private float m_RotationSpeed = 0.0f;
/// <summary>
/// 角色完成转向
/// </summary>
private bool m_RotationOver = false;
/// <summary>
/// 角色控制器
/// </summary>
private CharacterController m_CharacterController;
private void Start()
{
m_CharacterController = transform.GetComponent<CharacterController>();
}
private void Update()
{
//1.让角色始终贴紧地面
if (!m_CharacterController.isGrounded)
{
m_CharacterController.Move((transform.position + new Vector3(0.0f, -1000.0f, 0.0f)) - transform.position);
}
//2.点击鼠标左键 获得目标位置
if (Input.GetMouseButtonUp(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.collider.gameObject.name.Equals("Ground", System.StringComparison.CurrentCultureIgnoreCase))
{
m_TargetPos = hitInfo.point;
m_RotationOver = false;
m_RotationSpeed = 0.0f;
}
}
}
//3.根据目标位置和当前位置判断 是否应该移动和转向
if (m_TargetPos != Vector3.zero)
{
if (Vector3.Distance(m_TargetPos, transform.position) > 0.1f)
{
Vector3 direction = m_TargetPos - transform.position;
direction = direction.normalized;
direction.y = 0.0f;
//1.转向
if (!m_RotationOver)
{
m_RotationSpeed += 5.0f;
m_DirectionQua = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Lerp(transform.rotation, m_DirectionQua, m_RotationSpeed * Time.deltaTime);
if (Quaternion.Angle(transform.rotation, m_DirectionQua) < 0.1f)
{
m_RotationOver = true;
m_RotationSpeed = 1.0f;
}
}
//2.移动
m_CharacterController.Move(direction * m_Speed * Time.deltaTime);
}
}
}
}