Unity类原神角色旋转

大概思路就是:

首先通过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
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值