如果你在Unity里面使用了Rigidbody, 并且勾选了Is Kinematic 想自己通过Transfrom来控制角色的位置的话。那么你一定会碰到如果角色跑动快了,会插入到其他运动的角色或者静止的单位中,比如墙壁,建筑等等。
1:网上的解决方案: (老的解决方案)
网上到是有解决方案,不过都太复杂,都需要自己去预判下一步的步长,这个就是以前的没有引擎的老方法,原理就是如果下一步会被碰到就把下一步的位置直接设置到碰撞的边缘,而不是走满那一步。既然说到这里我们就要说一下Unity带来的全新的解决方案,使用球状射线的原理。Unity摘录如下:
2:我的解决方案(球体射线碰撞)
Physics.SphereCast 球体投射
static function SphereCast (origin : Vector3, radius : float, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Parameters参数
-
originThe center of the sphere at the start of the sweep.
在扫描起点的球体中心点。 -
radiusThe radius of the sphere.
球体的半径。 -
directionThe direction into which to sweep the sphere.
球体扫描的方向 -
hitInfoIf true is returned, hitInfo will contain more information about where the collider was hit (See Also: RaycastHit).
如果返回true,hitInfo将包含碰到器碰撞的更多信息。 -
distanceThe length of the sweep
扫描的长度 -
layerMaskA Layer mask that is used to selectively ignore colliders when casting a capsule.
根据Layer mask层的不同来忽略碰撞体。
Returns
boolean - True when the capsule sweep intersects any collider, otherwise false.
当胶囊物体投射时与碰撞体相交时,返回真,否则返回假。
原理: 把你的角色当成一个球型包围的物体,以他为中心,像一个球体发射射线,如果射线检查到碰撞体那么就认为碰撞了,然后就该处理你自己的逻辑,比如让角色停止,反弹,等等。以下是我在游戏中用到的
//0.7米处有碰撞急停 void Update () { RaycastHit hit; Vector3 p1 = transform.position; Vector3 p2 = p1 + Vector3.forward * 0.5f; if(Physics.CapsuleCast(p1, p2, 0.0f, transform.forward, out hit, 0.2f)) {
//停止该角色 CActionControl.Instance().OnStopMove(uqid_); } }
3:说一说当初实现的方案以及为什么不行
最初想法是MonoBehaviour.OnCollisionEnter 使用这个接口来检测碰撞,但是这个接口只会检测出你碰撞的瞬间。也就是说你碰撞提接触的瞬间,但是并不会保证你没有在碰撞了。也就是说MonoBehaviour.OnCollisionStay状态可能一直存在,那么你下次就无法检测是否碰撞了,甚至到后来可能会两个角色都合体了。
也并不是说这个方案实现不了,但是会非常的复杂,比如你想反弹,当两个角色发生了MonoBehaviour.OnCollisionEnter的时候就按照碰撞方向的反方向进行反弹操作,具体的反弹代码只能自己去实现了(由于你是自己控制的Transfrom),而且如果对象多了的话可能会导致,对象像荡秋千一样弹过去了又弹过来。所以这里避免了这种情况,表示这种实现方案在游戏中很难做到!