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