大概思路就是:
首先通过InputSystem来获取角色的WASD的返回值,将Vector2类型转换为Vector3类型,然后将其转换为弧度角(float),接着更新角度将摄影机旋转的Y轴角度也添加进来。判断我们的方向角度是否改变为其他角度,更新目标旋转角度数据。最后将角度数据转换为四元数。用Rigidbody.AddForce移动。Mathf.SmoothDampAngle来实现阻尼效果,最后转换四元数,通过Rigidbody.MoveRotation来进行旋转。
通过InputSystem来获取角色的WASD的返回值,将Vector2类型转换为Vector3类型
Vector3 movementDirection = GetMovementInputDirection();
//获取移动输入方向
protected Vector3 GetMovementInputDirection()
{
//转换为x轴和z轴,在Unity中Y轴是上下垂直的的轴
return new Vector3(movementInput.x, 0, movementInput.y);
}
然后将其转换为弧度角(float),接着更新角度将摄影机旋转的Y轴角度也添加进来。判断我们的方向角度是否改变为其他角度,更新目标旋转角度数据。
float targetRotationYAngle = Rotate(movementDirection);
private float Rotate(Vector3 direction)
{
//更新目标角度
float directionAngle = UpdateTargetRotation(direction);
//朝目标旋转方向旋转
RotateTowardsTargetRotation();
return directionAngle;
}
//更新目标角度
protected float UpdateTargetRotation(Vector3 direction, bool shouldConsiderCamerRotation = true)
{
//获取方向角度
float directionAngle = GetDirectionAngle(direction);
if (shouldConsiderCamerRotation)
{
//把相机旋转的角度也添加进来
directionAngle = AddCameraRotationToAbgle(directionAngle);
}
// 当我们的方向角度改变为其他角度时
if (directionAngle != currentTargetRotation.y)
{
//更新目标旋转角度数据
UpdateTargetRotationData(directionAngle);
}
return directionAngle;
}
//获取方向角度
protected float GetDirectionAngle(Vector3 direction)
{
//计算弧度角
float directionAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
if (directionAngle < 0f)
{
directionAngle += 360f;
}
return directionAngle;
}
//将相机旋转添加到 Abgle
protected float AddCameraRotationToAbgle(float abgle)
{
abgle += stateMachine.Player.MainCameraTransform.eulerAngles.y;
if (abgle > 360f)
{
abgle -= 360f;
}
return abgle;
}
protected void UpdateTargetRotationData(float targetAngle)
{
//我们需要重置经过的时间并将目标旋转设置为心角度
currentTargetRotation.y = targetAngle;
dampedTargetRotationPassedTime.y = 0f;
}
protected void RotateTowardsTargetRotation()
{
float currentYAngle = stateMachine.Player.Rigidbody.rotation.eulerAngles.y;
if (currentYAngle == currentTargetRotation.y)
{
return;
}
//Mathf.SmoothDampAngle:随时间推移将以度为单位给定的角度逐渐改变为所需目标角度。
float smoothedYangle = Mathf.SmoothDampAngle(currentYAngle, currentTargetRotation.y, ref dampedTargetRotationCurrentVelocity.y, timeToReachTargetRotation.y - dampedTargetRotationPassedTime.y);
dampedTargetRotationPassedTime.y += Time.deltaTime;
// 使用了 Quaternion.Euler 方法将平滑处理后的角度 smoothedYangle 转换成四元数
Quaternion targetRotation = Quaternion.Euler(0f, smoothedYangle, 0f);
// 使用 MoveRotation 方法将角色的旋转设置为目标旋转
stateMachine.Player.Rigidbody.MoveRotation(targetRotation);
}
Mathf.SmoothDampAngle来实现阻尼效果,最后转换四元数,通过Rigidbody.MoveRotation来进行旋转。
protected void RotateTowardsTargetRotation()
{
float currentYAngle = stateMachine.Player.Rigidbody.rotation.eulerAngles.y;
if (currentYAngle == currentTargetRotation.y)
{
return;
}
//Mathf.SmoothDampAngle:随时间推移将以度为单位给定的角度逐渐改变为所需目标角度。
float smoothedYangle = Mathf.SmoothDampAngle(currentYAngle, currentTargetRotation.y, ref dampedTargetRotationCurrentVelocity.y, timeToReachTargetRotation.y - dampedTargetRotationPassedTime.y);
dampedTargetRotationPassedTime.y += Time.deltaTime;
// 使用了 Quaternion.Euler 方法将平滑处理后的角度 smoothedYangle 转换成四元数
Quaternion targetRotation = Quaternion.Euler(0f, smoothedYangle, 0f);
// 使用 MoveRotation 方法将角色的旋转设置为目标旋转
stateMachine.Player.Rigidbody.MoveRotation(targetRotation);
}
最后将角度数据转换为四元数。用Rigidbody.AddForce移动。
private void Move()
{
if (movementInput == Vector2.zero || speedModifier == 0f)
{
return;
}
Vector3 movementDirection = GetMovementInputDirection();
float targetRotationYAngle = Rotate(movementDirection);
//计算游戏对象应当朝向的方向。
Vector3 taragetRotationDirection = GetTaragetRotationDirection(targetRotationYAngle);
float movementSpeed = GetMovementSpeed();
Vector3 currentPlayerHorizontaVelocity = GetPlayerHorizontalVelocity();
stateMachine.Player.Rigidbody.AddForce(taragetRotationDirection * movementSpeed - currentPlayerHorizontaVelocity, ForceMode.VelocityChange);
}
源码
using UnityEngine;
public class PlayerMovementState : IState
{
protected PlayerMovementStateMachine stateMachine;
protected Vector2 movementInput;
protected float baseSpeed = 5f;
protected float speedModifier = 1f;
//当前目标旋转
protected Vector3 currentTargetRotation;
//达到目标旋转的时间
protected Vector3 timeToReachTargetRotation;
// 阻尼目标旋转当前速度
protected Vector3 dampedTargetRotationCurrentVelocity;
//阻尼目标旋转经过时间
protected Vector3 dampedTargetRotationPassedTime;
// 构造函数,接受一个 PlayerMovementStateMachine 对象并进行初始化
public PlayerMovementState(PlayerMovementStateMachine playerMovementStateMachine)
{
stateMachine = playerMovementStateMachine;
InitializeData();
}
private void InitializeData()
{
timeToReachTargetRotation.y = 0.14f;
}
#region IState 方法
public void Enter()
{
Debug.Log("状态:" + GetType().Name);
}
public void Exit()
{
}
public void HandleIuput()
{
ReadMovementInput();
}
public void PhysicsUpdate()
{
Move();
}
public void Update()
{
}
#endregion
#region 主要方法
//读取移动输入
private void ReadMovementInput()
{
//读取PlayerInputActions中的Movement返回的值 (0,0),(0.71,0.71)
movementInput = stateMachine.Player.Input.PlayerActions.Movement.ReadValue<Vector2>();
}
private void Move()
{
if (movementInput == Vector2.zero || speedModifier == 0f)
{
return;
}
Vector3 movementDirection = GetMovementInputDirection();
float targetRotationYAngle = Rotate(movementDirection);
//计算游戏对象应当朝向的方向。
Vector3 taragetRotationDirection = GetTaragetRotationDirection(targetRotationYAngle);
float movementSpeed = GetMovementSpeed();
Vector3 currentPlayerHorizontaVelocity = GetPlayerHorizontalVelocity();
stateMachine.Player.Rigidbody.AddForce(taragetRotationDirection * movementSpeed - currentPlayerHorizontaVelocity, ForceMode.VelocityChange);
}
//控制角色在按键和摄像机的结合下移动
private float Rotate(Vector3 direction)
{
//更新目标角度
float directionAngle = UpdateTargetRotation(direction);
//朝目标旋转方向旋转
RotateTowardsTargetRotation();
return directionAngle;
}
#endregion
#region 可重用方法
//获取移动输入方向
protected Vector3 GetMovementInputDirection()
{
//转换为x轴和z轴,在Unity中Y轴是上下垂直的的轴
return new Vector3(movementInput.x, 0, movementInput.y);
}
protected float GetMovementSpeed()
{
return baseSpeed * speedModifier;
}
protected Vector3 GetPlayerHorizontalVelocity()
{
Vector3 playerHorizontalVelocity = stateMachine.Player.Rigidbody.velocity;
playerHorizontalVelocity.y = 0f;
return playerHorizontalVelocity;
}
//将相机旋转添加到 Abgle
protected float AddCameraRotationToAbgle(float abgle)
{
abgle += stateMachine.Player.MainCameraTransform.eulerAngles.y;
if (abgle > 360f)
{
abgle -= 360f;
}
return abgle;
}
//获取方向角度
protected float GetDirectionAngle(Vector3 direction)
{
//计算弧度角
float directionAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
if (directionAngle < 0f)
{
directionAngle += 360f;
}
return directionAngle;
}
protected void RotateTowardsTargetRotation()
{
float currentYAngle = stateMachine.Player.Rigidbody.rotation.eulerAngles.y;
if (currentYAngle == currentTargetRotation.y)
{
return;
}
//Mathf.SmoothDampAngle:随时间推移将以度为单位给定的角度逐渐改变为所需目标角度。
float smoothedYangle = Mathf.SmoothDampAngle(currentYAngle, currentTargetRotation.y, ref dampedTargetRotationCurrentVelocity.y, timeToReachTargetRotation.y - dampedTargetRotationPassedTime.y);
dampedTargetRotationPassedTime.y += Time.deltaTime;
// 使用了 Quaternion.Euler 方法将平滑处理后的角度 smoothedYangle 转换成四元数
Quaternion targetRotation = Quaternion.Euler(0f, smoothedYangle, 0f);
// 使用 MoveRotation 方法将角色的旋转设置为目标旋转
stateMachine.Player.Rigidbody.MoveRotation(targetRotation);
}
protected void UpdateTargetRotationData(float targetAngle)
{
//我们需要重置经过的时间并将目标旋转设置为心角度
currentTargetRotation.y = targetAngle;
dampedTargetRotationPassedTime.y = 0f;
}
//更新目标角度
protected float UpdateTargetRotation(Vector3 direction, bool shouldConsiderCamerRotation = true)
{
//获取方向角度
float directionAngle = GetDirectionAngle(direction);
if (shouldConsiderCamerRotation)
{
//把相机旋转的角度也添加进来
directionAngle = AddCameraRotationToAbgle(directionAngle);
}
// 当我们的方向角度改变为其他角度时
if (directionAngle != currentTargetRotation.y)
{
//更新目标旋转角度数据
UpdateTargetRotationData(directionAngle);
}
return directionAngle;
}
//使用四元数和向量来计算基于特定角度的方向向量。
// 这个方法接收一个目标角度 targetAngle(相对于Y轴的角度),并返回这个角度对应的前方向量(Vector3.forward)。
// 这可以用于计算游戏对象应当朝向的方向。
protected Vector3 GetTaragetRotationDirection(float targetAngle)
{
return Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
}
#endregion
}