Menu
CoddyTech

推动物体

本课属于 Coddy Unity 学习旅程的“打造真正的游戏”单元。第 41 课,共 60 课。

CharacterController 不会推动任何东西:让它撞上带有 Rigidbody 的箱子时,它会像撞到墙一样停下来。相反,对于每个 Move 碰到的碰撞体(包括地面),Unity 都会在控制器自己的脚本上调用 OnControllerColliderHit(ControllerColliderHit hit),由脚本决定接下来会发生什么。hit.collider 是被碰到的对象,hit.moveDirection 是碰到它的 Move 的方向,hit.normal 是接触点处表面的朝向。下面是 Unity 自带的推动脚本:

public float pushPower = 2f;

void OnControllerColliderHit(ControllerColliderHit hit)
{
    Rigidbody body = hit.collider.attachedRigidbody;
    if (body == null || body.isKinematic) return;   // 没有可推动的物体
    if (hit.moveDirection.y < -0.3f) return;        // 它在我们脚下

    Vector3 pushDir = new Vector3(hit.moveDirection.x, 0f, hit.moveDirection.z);
    body.linearVelocity = pushDir * pushPower;
}

每个 return 都有原因。地面和墙壁没有 Rigidbody,所以它们的 body 为 null,而且几乎每次 Move 都会碰到它们。运动学刚体只有在自己的脚本移动它时才会移动,所以给它设置速度不会产生作用。向下倾斜的 Move 碰到的是脚下的东西,不应该推开玩家站着的箱子。

推动方向只保留 x 和 z 分量,因此箱子会沿着地面滑动,而不会被压进地面。设置 linearVelocity,而不是施加力,可以让轻箱子和重箱子以相同的速度移动;使用 body.AddForce(pushDir * pushPower, ForceMode.Impulse) 则会较少地推动重箱子。

challenge icon

挑战

中等

让玩家踢到它碰上的球。

  1. 在 Kicker.cs 中,编写 void OnControllerColliderHit(ControllerColliderHit hit),并获取 Rigidbody body = hit.collider.attachedRigidbody;。
  2. 如果 body 为 null 或处于运动学状态,或者 hit.moveDirection.y < -0.3f(球在脚下),就执行 return。
  3. 将 body.linearVelocity 设为行走方向(y 为 0)乘以 kickPower,再加上 Vector3.up * lift。

按“开始”,然后走向红球:它会向前上方飞去。接着点击“检查”。

亲手试试

using UnityEngine;

public class Kicker : MonoBehaviour
{
    public float kickPower = 6f;
    public float lift = 4f;

    // 踢开玩家碰到的球
}

打造真正的游戏中的所有课

自己练习: Unity 在线编辑器