推动物体
本课属于 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) 则会较少地推动重箱子。
挑战
中等让玩家踢到它碰上的球。
- 在
Kicker.cs中,编写void OnControllerColliderHit(ControllerColliderHit hit),并获取Rigidbody body = hit.collider.attachedRigidbody;。 - 如果
body为 null 或处于运动学状态,或者hit.moveDirection.y < -0.3f(球在脚下),就执行return。 - 将
body.linearVelocity设为行走方向(y 为 0)乘以kickPower,再加上Vector3.up * lift。
按“开始”,然后走向红球:它会向前上方飞去。接着点击“检查”。
亲手试试
using UnityEngine;
public class Kicker : MonoBehaviour
{
public float kickPower = 6f;
public float lift = 4f;
// 踢开玩家碰到的球
}
打造真正的游戏中的所有课
自己练习: Unity 在线编辑器