CharacterController.Move
本课属于 Coddy Unity 学习旅程的“打造真正的游戏”单元。第 38 课,共 60 课。
CharacterController 是 Unity 中用于控制行走角色的组件:它是一个胶囊体,只有在你的脚本调用 controller.Move(motion) 时才会移动。motion 表示这一帧要移动的距离,因此它等于速度乘以 Time.deltaTime。Move 会让胶囊体沿墙壁滑动,而不是穿过墙壁;它可以爬上坡度不超过 Slope Limit(45 degrees)的斜坡,也可以踏上高度不超过 Step Offset(0.3 units)的台阶。它不是 Rigidbody:没有力、重力或反弹,也不会被任何东西推动。它会准确移动到 Move 指定的位置,这正是精确控制游戏角色所需要的。
重力需要你自行添加,寻找地面也是如此。如果上一次 Move 碰到了下方的物体,isGrounded 就为 true,因此不包含向下移动的 Move 永远找不到地面。短于控制器 Min Move Distance(0.001)的 Move 完全不会产生效果,所以,如果控制器只向侧面移动,那么它一停下来,就会报告自己没有接触地面。这个快递员用方向键行走,并在每次移动时稍微向下施压:
public class Courier : MonoBehaviour
{
public float speed = 6f;
CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
move.y = -2f; // 始终向下施加一点力,以便检测到地面
controller.Move(move * Time.deltaTime);
if (!controller.isGrounded)
{
Debug.Log("Off the ground");
}
}
}胶囊体与接触到的物体之间始终保持 Skin Width(0.08)的距离,因此,在 y = 0 的地面上,高度为 2 unit 的控制器会停在 y = 1.08,而不是 y = 1。Move 会从物理系统上一次检测到控制器的位置开始移动,因此,设置控制器的 transform.position 后,下一次 Move 可能会撤销这一设置。要传送控制器,先设置 controller.enabled = false,移动它,然后再启用它。
挑战
中等用它的 CharacterController 控制 explorer 行走,这样墙就能挡住它。
- 在
Update()中,根据 x 轴上的Input.GetAxisRaw("Horizontal")和 z 轴上的Input.GetAxisRaw("Vertical")构建Vector3 move,再乘以speed。 - 设置
move.y = -fallSpeed;,并调用controller.Move(move * Time.deltaTime);。 - 然后,当
controller.isGrounded为真时,将rend.material.color设置为Color.green,否则设置为Color.red。
按“开始”,让 explorer 撞上墙,再从左侧边缘走出去:它会变红并落下,着地后变绿。然后点击“检查”。
亲手试试
using UnityEngine;
public class Explorer : MonoBehaviour
{
public float speed = 4f;
public float fallSpeed = 3f;
CharacterController controller;
Renderer rend;
void Start()
{
controller = GetComponent<CharacterController>();
rend = GetComponent<Renderer>();
}
void Update()
{
// 用 controller.Move 移动,然后根据 isGrounded 为探险者设置颜色
}
}
打造真正的游戏中的所有课
自己练习: Unity 在线编辑器