bla*_*ole 8 c# collision-detection unity-game-engine
我正在尝试寻找其他注册冲突的方法(除了OnCollisionEnter()
和之外OnCollisionExit()
).我目前正在使用Physics.OverlapBox()
,但我需要有关碰撞的更多信息; 即,正常,点.
我可以使用Physics.BoxCast()
,但问题是它移动一个给定距离的盒子,使用maxDistance = 0f
将无法工作.
我需要一种检查碰撞类似的方法,Physics.OverlapBox()
除了它还会返回有关转换中所有碰撞的信息.
任何帮助表示赞赏.谢谢.
您可以使用OverlapBox
和 使用Collider
来ClosestPoint
选择单个重叠点,并使用它来进行碰撞计算。
Collider[] cols = Physics.OverlapBox(...);
Vector3 myPosition = transform.position; // for example
foreach (Collider col in cols) {
Vector3 closestPoint = col.ClosestPoint(myPosition);
Vector3 positionDifference = (closestPoint-myPosition);
Vector3 overlapDirection = positionDifference.normalized;
}
Run Code Online (Sandbox Code Playgroud)
这overlapDirection
将指向远离您使用的位置ClosestPoint
到每个碰撞体中心的方向。如果你想要基于物体表面的东西,你可以做的是使用重叠方向来放置瞄准你的物体的光线投射,以这种方式找到法线:
// ...
foreach (Collider col in cols) {
Vector3 closestPoint = col.ClosestPoint(myPosition);
Vector3 positionDifference = (closestPoint-myPosition);
Vector3 overlapDirection = positionDifference.normalized;
RaycastHit hit;
int layerMask = 1; // Set to something that will only hit your object
float raycastDistance = 10.0; // something greater than your object's largest radius,
// so that the ray doesn't start inside of your object
Vector3 rayStart = myPosition + overlapDirection * raycastDistance;
Vector3 rayDirection = -overlapDirection ;
if (Physics.Raycast(rayStart, rayDirection, out hit, Mathf.Infinity, layerMask)) {
Debug.Log(hit.normal);
Debug.Log(hit.position);
} else {
// The ray missed your object, somehow.
// Most likely it started inside your object
// or there is a mistake in the layerMask
}
}
Run Code Online (Sandbox Code Playgroud)
您在第一个答案的评论中表达的担忧是有效的,但坏消息是没有简单的技巧可以解决它。您应该寻找的是所谓的连续碰撞检测,其简化版本在我关于类似问题的回答中描述:
基本上,对于场景中的每个移动物体,您必须在帧的一部分内计算下一次碰撞的时刻
0<t0<1
,然后将位置前进到帧内的时刻 t0,更新由于碰撞而产生的速度,并进一步进行下一次碰撞t0<t1<1
,直到您到达tn=1
(帧结束)的时间,确保您不会由于计算的舍入或“角落”对象而卡在帧的中间。对于球形碰撞器,通常通过使用胶囊与胶囊(对于对象对)相交和胶囊与盒子作为边界来完成。
与我所指的答案中的简单引擎相反,Unity 具有连续的碰撞检测功能。因此,您可以启用连续碰撞和连续动态,这在计算上是非常昂贵的。
您还可以尝试使用RigidBody.SweepTest,它会返回最接近的碰撞信息。请注意,即使还有RigidBody.SweepTestAll,它也没有多大帮助。不仅因为它仅返回前 128 个碰撞,还因为它不处理它们,因为没有反射。对于物理上正确的行为,您必须执行上述操作 - 提前时间直到第一次碰撞并更新速度。无论是使用物理引擎还是您自己。这是非常昂贵的,并且没有多少游戏这样做,甚至使用简化的对象进行作弊(球体是最便宜的,因为两个扫过的球体是两个胶囊,它们的交集是一个相对便宜的计算),但是步骤量很大,特别是在“角落”中“当物体无处可去并因此不断碰撞的情况可能会非常大,而且这种情况发生的次数超出了人们的预期。
对于复杂的对象,您不太可能比 SweepTest 做得更好,除非您基于更简单的原语(例如Physics.BoxCast
或 )触发它Physics.SphereCast
。同样,即使有Physics.BoxCastAll
,Physics.SphereCastAll
它们也不是特别有用,因为只能保证发生第一次碰撞。这些 xxxCastAll 是您编写的您正在寻找的函数,因此请尝试一下,它们可能足以满足您的用例。