Unity 角色控制器的几种实现方式(CharacterController驱动,刚体驱动,动画驱动)

一.CharacterController组件驱动

这是常用的角色控制方式,但是最大的缺点就是无法被力所驱动,因此,很难做出冲撞的抵触效果

另外这里要说明:

第一种:characterController.SimpleMove(Speed);
第二种:characterController.Move(Speed*deltaTime);
发生的问题:第一种和第二种垂直移动效果不同。
解决:官方文档:第一种始终使用的是系统的默认垂直加速度,而第二种要自己实现。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 角色控制器控制角色物理效果
/// </summary>
public class PlayerControllerTest00 : MonoBehaviour
{
    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
    private Vector3 moveDirection = Vector3.zero;

    void Update()
    {
        CharacterController controller = GetComponent<CharacterController>();
        if (controller.isGrounded)
        {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetKeyDown(KeyCode.Space))
                moveDirection.y = jumpSpeed;
        }

        moveDirection.y -= gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
    }
}

这里借用了某位老兄的代码:https://www.cnblogs.com/ChenZiRong1999/p/13395132.html

这里产生了一个疑问,如果有知道的网友,给我留个评论:

遇到一个玄学Bug,用角色控制器做了一个角色控制组件,采用两种方式:
第一种:角色外层根用空物体然后挂上组件,动画模型物体作为子物体。
第二种:动画模型物体直接为根物体,并且模型没有位移动画。
移动代码charactorController.SimpleMove(verticalSpeed+horizonSpeed);
发生的问题:第一种比第二种飘,也就是从一个物体边缘走出去落下的过程中第一种很飘,貌似垂直速度不符合效果。

二.刚体驱动

这里使用胶囊碰撞体加刚体组件的方式来实现,从而可以实现冲撞效果,缺点是需要大量的时间来调整,而且代码干涉物理效果,并且物理更新与渲染更新并不同步,因此角色的移动会相对看起来比较抖动,当然无论代码是放在FixedUpdate()还是Update()都和很难完全消除抖动,更多的是从相机动手,让相机的跟随抵消不同步抖动带来的视觉干扰。

在刚体下有几种移动方式,具体如代码中所示。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 刚体角色控制器控制角色
/// </summary>
public class PlayerControllerTest01 : MonoBehaviour
{
    Rigidbody rigid;

    public float moveSpeed;
    private Vector3 moveDirection = Vector3.zero;//角色的方向
    float moveScale = 0;
    private void Awake()
    {
        rigid = GetComponent<Rigidbody>();
    }

    private void Update()
    {

        //跳跃:为刚体施加一个向上的力:该力是由向上的跳跃速度和在刚体原速度方向上的一个速度合成的
        //VelocityChange是一个瞬时速度
        if (Input.GetKeyDown(KeyCode.Space)) {
            rigid.AddForce(transform.up * 20 /*+ rigid.velocity.normalized * directionalJumpFactor*/, ForceMode.VelocityChange);
        }
        
        moveScale = 0;
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S))
        {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveScale = 1;
        }

        //旋转,使用刚体的旋转
        Quaternion rot = Quaternion.Euler(0, Vector3.SignedAngle(Vector3.forward, moveDirection, Vector3.up), 0);//目标旋转
        Quaternion currentRot = Quaternion.RotateTowards(rigid.rotation, rot, Time.deltaTime * 600);//中间插值旋转
        rigid.MoveRotation(currentRot);

        //水平移动
        Vector3 v = Vector3.Project(rigid.velocity, transform.forward);
        float s = moveSpeed == 0 ? 0 : 1 - v.magnitude / moveSpeed;
        //rigid.AddForce(transform.forward * moveScale * s, ForceMode.VelocityChange);//第一种:力驱动,好处:比较真实具体移动交给物理系统;缺点:不好控制,容易滑动
        //rigid.velocity = transform.forward * 10 * moveScale + Vector3.up * rigid.velocity.y;//第二种:速度设置,好处:直接设置速度;缺点:直接干涉物理速度,抖动失真
        //if (moveScale == 1) rigid.MovePosition((rigid.position + transform.forward * moveSpeed * Time.deltaTime));//第三种:直接物理位置,好处:直接移动,缺点:目前描述不出来
    }

    private void FixedUpdate()
    {
        if (moveScale == 1) rigid.MovePosition((rigid.position + transform.forward * moveSpeed * Time.fixedDeltaTime));
    }
}

 同样,参考某位老兄的代码:https://blog.csdn.net/qq_38327432/article/details/91561247

二.动画驱动

顾名思义,这里代码只是改变动画状态机的状态参数,移动动画自身带有位移,这样的好处就是动画效果和位移等效果完美契合,整个的动画都交由动画师来完成,缺点是整个过程的动画参数量大,至于动画遇到的问题,做的少,暂时不知道。代码demo,暂时没有资源,没有做

写了半天必须配张图啊

原文地址:https://www.cnblogs.com/xiaoahui/p/13765561.html