这一节我们实现石头人的远程攻击:让它扔出一块石头砸向角色人物。
1. 制作石头预制体
我们从素材中将石头拖拽到场景中。因为石头是被抛出来的,需要模拟重力,因此我们添加 Rigidbody 刚体组件。
同时石头与地面要产生碰撞,所以也要添加碰撞体。我们不使用之前使用过的盒子或胶囊碰撞体,范围太粗糙,无法模拟石头真实的碰撞效果。此处我们使用 Mesh Collider 碰撞体,如图 1 所示,需要勾选 Convex。可以在场景中看到 Mesh Collider 设置的范围很贴合。
2. 创建石头控制脚本
因为石头是需要实时生成的,它自己控制自己的生命周期逻辑会更方便一点,所以我们也会石头创建一个脚本,命名为 RockController。
代码清单 1 是石头的控制器代码,在刚创建时(Satrt)就飞向角色人物(FlyToTarget)。飞向人物使用 Rigidbody.AddForce() 函数实现,其指明加的力(方向和大小)和力的类型。我们再往上面加力,防止石头坠落太快。
飞向的角色由外部指定,通过 SetTarget() 函数指定。
实现完代码后,我们将 RockController 拖拽到石头上,这时候石头的组件已经全部准备完毕。因为初始场景中不需要石头,我们将 Hierarchy 窗体中的石头拖拽到 Assets 窗体,制作成预制体,供后续生成。最后删除 Hierarchy 窗体中原本的石头对象。
3. 实现投掷功能
我们回到石头人控制器中实现投掷石头。投掷石头的时机也通过动画事件指定,如代码清单 2 所示,此处定义了 ThrowRock() 事件函数。
代码里声明了两个变量,一个是石头的预制体,一个是石头人右手的位置。这两个变量都在外部预先指定。投掷的逻辑是,在投掷时通过石头预制体创建石头,其位置在石头人左手处;接着设置角色的位置;然后在石头初始化完成后会飞向角色位置。
还是时序问题感觉拿捏不准:石头人处的 SetTarget() 需要在石头的 Start() 之前完成。这点不确定,但是运行起来没有问题。
逻辑实现好后,我们就可以在外部指定石头预制体和石头人的右手位置。如图 2 所示,右手位置可以使用模型上现有的位置大致指定。
修复无法攻击的问题
石头人的占地面积比较大,碰撞相关设置参数都比较大,会出现人物一直走不到指定敌人位置,而无法攻击的情况。我们通过修改 stoppingDistance 和判断条件来改善。
如代码清单 3 所示,我们在 Awake() 时记录初始 stoppingDistance 值。攻击时计算两者之间的碰撞距离,和攻击距离比较,选取其中的较大值。并以此更新 stoppingDistance 值和判断条件值。在人物移动的时候,恢复为初始的 stoppingDistance 值。
最终效果如图 3 所示,角色靠近石头人后会投掷石头。角色走近石头人攻击时速度有点奇怪。
碰撞范围大了之后,人物走近速度会变慢,效果看着非常奇怪。不知道哪里出了问题。