66.CharacterController角色控制器

66.3D动画-角色控制器


66.1 知识点

CharacterController角色控制器是什么

角色控制器是让角色可以受制于碰撞,但是不会被刚体所牵制。
如果我们对角色使用刚体判断碰撞,可能会出现一些奇怪的表现,比如在斜坡上往下滑动,不加约束的情况碰撞可能让自己被撞飞等等。
而角色控制器会让角色表现得更加稳定。
Unity提供了角色控制器组件专门用于控制角色。

注意:添加角色控制器后,不用再添加刚体。能检测碰撞函数。能检测触发器函数。

CharacterController角色控制器的使用

使用角色控制器建议取消Animator组件上的根运动

CharacterController角色控制器组件参数


  • Slope Limit(斜度限制):坡度度数限制,大于该值的斜坡上不去
  • Step Offset(每步偏移量):台阶偏移值,单位为米,低于这个值的台阶才能上去,该值不能大于角色控制器的高度
  • Skin Width(蒙皮宽度):皮肤的宽度,两个碰撞体可以穿透彼此最大的皮肤宽度,较大的值可以减少抖动,较小的值可能导致角色卡住,建议设置为半径的10%。通俗来说就是角色可以和刚体穿模多少。
  • MinMoveDistance(最小移动距离):大多数情况下为0,可以用来减少抖动

CharacterController角色控制器代码控制

CharacterController.isGrounded变量 是否接触了地面
//CharacterController中的isGrounded变量 是否接触了地面
//在上次移动期间 CharacterController 是否接触地面?
if ( characterController.isGrounded )
{
    print("接触地面了");
}
CharacterController.SimpleMove方法 受重力作用的移动
//CharacterController中的SimpleMove方法 受重力作用的移动
//以 speed 移动该角色。
characterController.SimpleMove(Vector3.forward * 10 * Time.deltaTime);
CharacterController.Move方法 不受重力作用的移动
//CharacterController中的Move方法 不受重力作用的移动
//为 GameObject 的移动提供附加的 CharacterController 组件。
characterController.Move(Vector3.forward * 10 * Time.deltaTime);
碰撞和触发检测函数
//当角色控制器想要判断和别的碰撞器产生碰撞时 使用该函数
private void OnControllerColliderHit(ControllerColliderHit hit)
{
    print("角色碰撞器发生碰撞"+hit.collider.gameObject.name);
}

//OnCollisionEnter方法对角色控制器没用 
//private void OnCollisionEnter(Collision collision)
//{
//    print("碰撞触发");
//}

//角色控制器可以检测触发器 OnTriggerEnter方法有用
private void OnTriggerEnter(Collider other)
{
    print("触发器触发");
}

66.2 知识点代码

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

public class Lesson66_3D动画_角色控制器 : MonoBehaviour
{
    private CharacterController characterController;
    private Animator animator;

    void Start()
    {
        #region 知识点一 角色控制器是什么?
        //角色控制器是让角色可以受制于碰撞,但是不会被刚体所牵制
        //如果我们对角色使用刚体判断碰撞,可能会出现一些奇怪的表现
        //比如:
        //1.在斜坡上往下滑动
        //2.不加约束的情况碰撞可能让自己被撞飞
        //等等
        //而角色控制器会让角色表现的更加稳定
        //Unity提供了角色控制器脚本专门用于控制角色

        //注意:
        //添加角色控制器后,不用再添加刚体
        //能检测碰撞函数
        //能检测触发器函数
        //能被射线检测
        #endregion

        #region 知识点二 角色控制器的使用
        //1.参数相关
        //2.代码相关
        characterController = this.GetComponent<CharacterController>();
        animator = this.GetComponent<Animator>();

        //关键变量

        //CharacterController中的isGrounded变量 是否接触了地面
        //在上次移动期间 CharacterController 是否接触地面?
        if ( characterController.isGrounded )
        {
            print("接触地面了");
        }

        //关键方法

        //CharacterController中的SimpleMove方法 受重力作用的移动
        //以 speed 移动该角色。
        //characterController.SimpleMove(Vector3.forward * 10 * Time.deltaTime);

        //CharacterController中的Move方法 不受重力作用的移动
        //为 GameObject 的移动提供附加的 CharacterController 组件。
        //characterController.Move(Vector3.forward * 10 * Time.deltaTime);

        #endregion
    }

    void Update()
    {
        animator.SetInteger("Speed", (int)Input.GetAxisRaw("Vertical"));

        //CharacterController中的Move方法 不受重力作用的移动
        //为 GameObject 的移动提供附加的 CharacterController 组件。
        //始终朝人物前面移动
        characterController.SimpleMove(this.transform.forward * 80 * Time.deltaTime * Input.GetAxisRaw("Vertical"));
        //characterController.Move(this.transform.forward * 80 * Time.deltaTime * Input.GetAxisRaw("Vertical"));

        //CharacterController中的isGrounded变量 是否接触了地面
        ////在上次移动期间 CharacterController 是否接触地面?
        if (characterController.isGrounded)
        {
            print("接触地面了");
        }
    }

    //当角色控制器想要判断和别的碰撞器产生碰撞时 使用该函数
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        print("角色碰撞器发生碰撞"+hit.collider.gameObject.name);
    }

    //OnCollisionEnter方法对角色控制器没用 
    //private void OnCollisionEnter(Collision collision)
    //{
    //    print("碰撞触发");
    //}

    //角色控制器可以检测触发器 OnTriggerEnter方法有用
    private void OnTriggerEnter(Collider other)
    {
        print("触发器触发");
    }

}

66.3 练习题

在之前的练习题基础上,加入角色控制器控制角色的移动

给模型添加角色控制器组件,取消Animator组件的根运动

创建平面光源立方体等

代码中得到角色控制器组件,写移动和选择逻辑

using UnityEngine;

public class Lesson66_练习题 : MonoBehaviour
{
    // 在之前的练习题基础上,加入角色控制器控制角色的移动
    private CharacterController characterController; // 定义一个CharacterController变量,用于存储角色控制器组件
    
    public float speed = 10; // 定义一个float变量,用于设置移动速度
    
    public float roundSpeed = 20; // 定义一个float变量,用于设置旋转速度
    
    void Start()
    {
        characterController = this.GetComponent<CharacterController>(); // 获取当前游戏对象上的CharacterController组件并赋值给characterController变量
    }
    
    void Update()
    {
        characterController.SimpleMove(this.transform.forward * speed * Time.deltaTime * Input.GetAxis("Vertical")); // 调用角色控制器的SimpleMove方法,沿着当前游戏对象的前方向移动,移动距离由speed、Time.deltaTime和垂直轴输入决定
        
        this.transform.Rotate(Vector3.up, roundSpeed * Time.deltaTime * Input.GetAxis("Horizontal")); // 调用当前游戏对象的Rotate方法,沿着世界坐标系的y轴旋转,旋转角度由roundSpeed、Time.deltaTime和水平轴输入决定
    }
}

66.4 练习题代码

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

public class Lesson66_练习题 : MonoBehaviour
{
    #region 练习题一 
    // 在之前的练习题基础上,加入角色控制器控制角色的移动

    private Animator animator; // 定义一个Animator变量,用于存储动画控制器组件

    public Transform headPos; // 定义一个Transform变量,用于存储头部的位置
    //x方向鼠标旋转了多少角度
    private float changeAngleX; // 定义一个float变量,用于记录x方向鼠标旋转了多少角度
    //y方向鼠标旋转了多少角度
    private float changeAngleY; // 定义一个float变量,用于记录y方向鼠标旋转了多少角度



    private CharacterController characterController; // 定义一个CharacterController变量,用于存储角色控制器组件

    public float speed = 10; // 定义一个float变量,用于设置移动速度

    public float roundSpeed = 20; // 定义一个float变量,用于设置旋转速度




    void Start()
    {
        animator = this.GetComponent<Animator>(); // 获取当前游戏对象上的Animator组件并赋值给animator变量



        characterController = this.GetComponent<CharacterController>(); // 获取当前游戏对象上的CharacterController组件并赋值给characterController变量
    }
    
    void Update()
    {
        animator.SetFloat("x", Input.GetAxis("Horizontal")); // 根据水平轴输入设置动画控制器中的x参数
        animator.SetFloat("y", Input.GetAxis("Vertical")); // 根据垂直轴输入设置动画控制器中的y参数

        if (Input.GetKeyDown(KeyCode.K)) // 如果按下K键
            animator.SetTrigger("Fire"); // 设置动画控制器中的Fire触发器

        //角度就在累加
        changeAngleX += Input.GetAxis("Mouse X"); // 根据鼠标水平轴输入累加changeAngleX变量
        changeAngleX = Mathf.Clamp(changeAngleX, -30, 30); // 将changeAngleX变量限制在-30到30之间

        changeAngleY += Input.GetAxis("Mouse Y"); // 根据鼠标垂直轴输入累加changeAngleY变量
        changeAngleY = Mathf.Clamp(changeAngleY, -30, 30); // 将changeAngleY变量限制在-30到30之间





        characterController.SimpleMove(this.transform.forward * speed * Time.deltaTime * Input.GetAxis("Vertical")); // 调用角色控制器的SimpleMove方法,沿着当前游戏对象的前方向移动,移动距离由speed、Time.deltaTime和垂直轴输入决定

        this.transform.Rotate(Vector3.up, roundSpeed * Time.deltaTime * Input.GetAxis("Horizontal")); // 调用当前游戏对象的Rotate方法,沿着世界坐标系的y轴旋转,旋转角度由roundSpeed、Time.deltaTime和水平轴输入决定
    }

    private void OnAnimatorIK(int layerIndex) // 当动画执行逆向动力学IK时调用该方法
    {
        animator.SetLookAtWeight(1, 1, 1); // 设置动画控制器的LookAt权重为1,表示完全受LookAt位置影响
        Vector3 pos = Quaternion.AngleAxis(changeAngleX, Vector3.up) * (headPos.position + headPos.forward * 10); // 根据changeAngleX变量和y轴,计算出一个旋转四元数,并用它旋转头部位置加上头部前方向乘以10的向量,得到一个新的位置
        pos = Quaternion.AngleAxis(changeAngleY, Vector3.right) * pos; // 根据changeAngleY变量和x轴,计算出一个旋转四元数,并用它旋转上一步得到的位置,得到最终的LookAt位置
        animator.SetLookAtPosition(pos); // 设置动画控制器的LookAt位置为pos
    }

    #endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏