• 第三人称角色控制器解析


    在unity的标准资源包中,包含了一个叫做 Third Person Controller的东西,这个东西是一个unity实现的角色控制器,下面来研究一下它是怎么实现的。

    这个控制系统,主要由以下几部分构成:

    • Third Person User Control
    • Third Person Character
    • 摄像机控制脚本

    下面一一讲解这些部分:

    首先 Third Person User Control 和 Third Person Character 都是挂到主角身上的,同时主角身上还应该有 Animator组件和 Rigidbody组件,类似于下图:

    Third Person User Control

      这个脚本主要是用于检测用户输入,然后将用户输入转化为具体的行为数据,传递给Third Person Character使用。

       private void FixedUpdate()
            {
                // read inputs
                float h = CrossPlatformInputManager.GetAxis("Horizontal");//获取水平输入
                float v = CrossPlatformInputManager.GetAxis("Vertical");//获取 垂直输入
                bool crouch = Input.GetKey(KeyCode.C); //获取C键输入
    
                // calculate move direction to pass to character
                if (m_Cam != null)//如果当前场景主摄像机不为空
                {
                    // calculate camera relative direction to move:
                    m_CamForward = Vector3.Scale(m_Cam.forward, new Vector3(1, 0, 1)).normalized;//获取当前摄像机的 forward 方向,并且将其y值设为0,然后归一化 这个变量
                    m_Move = v*m_CamForward + h*m_Cam.right;//移动方向为:垂直方向输入* 摄像机前方向 + 水平输入*摄像机右方向
                }
                else//如果主摄像机为空
                {
                    //移动方向为 世界坐标轴前方* 垂直输入 + 直接坐标轴右方*水平输入
                    m_Move = v*Vector3.forward + h*Vector3.right;
                }
    #if !MOBILE_INPUT
                // walk speed multiplier
                if (Input.GetKey(KeyCode.LeftShift)) m_Move *= 0.5f;
    #endif
    
                //传递给 Third Person Character
                m_Character.Move(m_Move, crouch, m_Jump);
                m_Jump = false;
            }

      这个脚本很简单,唯一有价值的地方就是它对于前进方向的计算,它以摄像机为基准来进行方向计算,这一点可以借鉴。

    Third Person Character

      这个脚本稍微要复杂一些,它会涉及到 角色的移动、动画的播放等。

      首先来看看它的Move方法,它用于控制 角色的移动:

     1     public void Move(Vector3 move, bool crouch, bool jump)
     2         {
     3 
     4             // convert the world relative moveInput vector into a local-relative
     5             // turn amount and forward amount required to head in the desired
     6             // direction.
     7 
     8             //如果输入的移动方向没有归一化,那么先将其归一化。
     9             if (move.magnitude > 1f) move.Normalize();
    10 
    11             /* transform.InverseTransformDirection(Vector3 dir)
    12              * 将 世界坐标系下的向量 dir 转化为 transform 自身坐标系下的向量
    13              */
    14             move = transform.InverseTransformDirection(move);
    15 
    16             //检测是否处于地面
    17             CheckGroundStatus();
    18 
    19             /* Vector3.ProjectOnPlane(Vector3 dir , Vector3 Normal)
    20              * Normal:垂直于一个平面A 的向量,也叫作平面A 的法线
    21              * 这个API的意思是,将 向量dir 投影到 法线Normal垂直的平面上,
    22              * 在这里也就是将  移动向量投影到 地面
    23              */
    24             move = Vector3.ProjectOnPlane(move, m_GroundNormal);
    25 
    26             //计算旋转角度,这里计算的是 move向量与 z轴正方向的夹角
    27             m_TurnAmount = Mathf.Atan2(move.x, move.z);
    28             m_ForwardAmount = move.z;
    29 
    30             //实现平滑加速的转向动画
    31             ApplyExtraTurnRotation();
    32 
    33             // control and velocity handling is different when grounded and airborne:
    34             //当在地上时
    35             if (m_IsGrounded)
    36             {
    37                 HandleGroundedMovement(crouch, jump);
    38             }
    39             else
    40             {
    41                 HandleAirborneMovement();
    42             }
    43 
    44             //处理蹲下时缩放胶囊体高度
    45             ScaleCapsuleForCrouching(crouch);
    46 
    47             PreventStandingInLowHeadroom();
    48 
    49             // send input and other state parameters to the animator
    50             //改变动画播放
    51             UpdateAnimator(move);
    52         }

    这个过程参见上图: 经过 controller 计算后,得到的 方向向量 为 S,然后传递给 Character 的move方法,move方法接收到S向量后,

    1. 将S向量由世界坐标系转化到了自身坐标系,变为向量 OD
    2. 将向量OD 投影到地面上,获得向量 OA
    3. 计算向量OA与 人物自身坐标系Z轴 的夹角 ∠ZOA
    4. 计算向量OA在 人物自身坐标系Z轴 的分量 z

    最终,计算到的角度值,会使用 transform.Rotate(float x,flaot y ,float z)方法进行旋转。

    而移动,则会交给Animator来控制,因为我们是使用的动画控制移动。

    接下来看看下一个方法:ApplyExtraTurnRotation()

    1 void ApplyExtraTurnRotation()
    2         {
    3             // help the character turn faster (this is in addition to root rotation in the animation)
    4             //由 180线性插值到 360,插值幅度为 前进分量在z轴上的分量,这里也就意味着,转向越大,那么转身速度增加得越慢
    5             float turnSpeed = Mathf.Lerp(m_StationaryTurnSpeed, m_MovingTurnSpeed, m_ForwardAmount);
    6 
    7             //m_TurnAmount =需要旋转的角度
    8             transform.Rotate(0, m_TurnAmount * turnSpeed * Time.deltaTime, 0);
    9         }

    至于最后一个的相机跟随,可以做简单的,可以做复杂的,这个可以使用 cinimatic camera插件

  • 相关阅读:
    国王游戏
    选数
    双塔
    线段树
    树状数组及其他特别简单的扩展
    折半搜索
    VUE项目
    git_基本使用
    同源
    axios-使用
  • 原文地址:https://www.cnblogs.com/leiGameDesigner/p/9072168.html
Copyright © 2020-2023  润新知