[Unity]如何解决带刚体的物体在墙角会穿墙的问题
问题背景
当一个物体在两个带碰撞体的方块组成的墙角时,只要“挤一挤”就可以从墙角穿墙而过:


原因分析
根据【Unity】Rigidbody.velocity 的陷阱一文,有以下结论:
使用transform.Translate(), transform.RotateAround(), rigidbody.MovePosition(), Vector3.MoveTowards() 等方法 “强制” 改变刚体的运动状态时,此时物体速度的改变并不会引发Rigidbody.velocity的改变,
- 如果仅使用
MovePosition()控制物体移动(称之为“仅移动”),刚体组件的velocity会一直为0 - 如果仅使用
AddForce()控制物体移动(称之为“仅受力”),它的velocity与真实速率一致 - 如果同时使用
MovePosition()和AddForce()控制物体移动,它的真实速率是“仅移动”和“仅受力”的效果之和,但velocity的数值和“仅受力”时一致
也就是说,物理系统只能理解由velocity的变化而产生的运动(施加力->产生加速度->产生速度/直接修改velocity),当对一个由物理系统控制的刚体使用物理系统以外的方法施加运动时,物理系统就无法正确处理该物体的物理行为了,而上述的穿墙bug也正是因为角色本身的移动是由MovePosition()控制的,导致物理系统无法正确处理在墙角处的碰撞判定
解决方案
通过修改velocity来实现角色移动:
private void Move() {
var speed = _properties.speed; //在编辑器中设置的角色的速度
var verAxis = Input.GetAxisRaw("Vertical");
var horAxis = Input.GetAxisRaw("Horizontal");
Vector3 input = new Vector3(horAxis, 0, verAxis);
_rigidbody.velocity = input * speed;
}
注意事项
transform.Translate()可能比较好理解,毕竟是通过直接修改transform组件来完成的运动,物理系统无法理解很正常,但是为什么rigidbody.MovePosition()也不行呢?翻一翻官方文档可以发现,Unity官方对这个方法的描述是:

“移动kinematic刚体到指定位置”,即该方法仅作用于运动学刚体,即不受物理系统控制,需要由各种变换方法直接控制物体移动的刚体,不适用于普通的遵循力学规律的刚体。

浙公网安备 33010602011771号