相对于静态分离轴算法,我们需要测试一个扩展的轴。显然这个是速度矢量轴。
那么我们现在有3个选择: 1. 间隔交叠
2. 间隔不相交,但是将在未来某个时刻发生碰撞 3. 间隔不相交,并且不会在未来发生碰撞
第三种可能性意味着物体不会在该帧处发生碰撞,而且分离轴真正分离了物体。因此物体不会发生碰撞。
AxisSeparatePolygons()函数将反映这种现象,并返回重叠量或者碰撞时间。为了区别两者,当检测到交叠时,将返回一个负值。如果检测到未来的碰撞,将返回一个正值。该函数看起来如下:
bool AxisSeparatePolygons(Vector Axis, Polygon A, Polygon B, Vector Offset,
Vector Vel,float& t,float tmax);
这里Offset是多边形A和多边形B之间的相对距离,并且Vel是多边形A相对于多边形B的相对速度。
求解碰撞平面的算法与MTD非常相似。只是碰撞将优于交叠,如果检测到未来的碰撞,将选择最新的一个。
如果没有发现碰撞并且只检测到了交叠,那么就像以前一样,选择交叠最小的那个轴。
碰撞检测函数将返回碰撞的法向,还有碰撞的深度(负值)和碰撞时间(正值)之一。最后的伪代码如下…
bool Collide(const Vector* A,int Anum,const Vector* B,int Bnum,const Vector& xOffset,const Vector& xVel,Vector& N,float& t) {
if(!A ||!B)
returnfalse; // All the separation axes
// note : a maximum of 32 vertices per poly is supported Vector xAxis[64];
float taxis[64]; int iNumAxes=0;
xAxis[iNumAxes]= Vector(-xVel.y, xVel.x); float fVel2 = xVel * xVel; if(fVel2 >0.00001f) {
if(!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes],t))
returnfalse; iNumAxes++; }
// 测试分离轴A
for(int j = Anum-1, i =0; i < Anum; j = i, i ++) {
Vector E0 = A[j]; Vector E1 = A[i]; Vector E = E1 - E0;
xAxis[iNumAxes]= Vector(-E.y, E.x); if(!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes],t))
returnfalse; iNumAxes++;
, ,, taxis[iNumAxes], , taxis[iNumAxes], xOffset xVel
xOffset xVel}
// 测试分离轴B
for(int j = Bnum-1, i =0; i < Bnum; j = i, i ++) {
Vector E0 = B[j]; Vector E1 = B[i]; Vector E = E1 - E0;
xAxis[iNumAxes]= Vector(-E.y, E.x);
if(!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, t))
returnfalse; iNumAxes++; }
if(!FindMTD(xAxis, taxis, iNumAxes, N, t))
returnfalse;
// 确保多边形被彼此推开。 if(N * xOffset <0.0f)
N =-N; returntrue;
}
bool AxisSeparatePolygons ( Vector N, Polygon A, Polygon B, Vector Offset, Vector Vel,float&t,float tmax)
{
float min0, max0; float min1, max1;
CalculateInterval(N, A, min0, max0);
CalculateInterval(N, B, min1, max1); float h = Offset dot N; min0 += h; max0 += h; float d0 = min0 - max1;
// 如果重叠, do < 0
taxis[iNumAxes],
float d1 = min1 - max0;
// 如果重叠, d1 > 0 // 分离,测试动态间隔 if(d0 >0.0f|| d1 >0.0f) {
float v = Vel dot N;
// 速度很小,所以只能进行重叠测试。 if(fabs(v)<0.0000001f)
returnfalse; float t0 =-d0 / v;
// 时间影响D0达到0 float t1 = d1 / v;
// 时间影响D0达到1 // 排序时间。 if(t0 > t1) {
float temp = t0; t0 = t1; t1 = temp; }
// 取最小值
taxis =(t0 >0.0f)? t0 : t1; // 交叉时间太晚或时间,没有碰撞
if(taxis <0.0f|| taxis > tmax)
returntrue; returnfalse; } else {
// 重叠。得到的区间,作为最小的|D0|和|D1| // 返回负数以标记为重叠 taxis =(d0 > d1)? d0 : d1;
returnfalse;
}
}
bool FindCollisionPlane (Vector* Axis,float* taxis,int iNumAxes, Vector& Ncoll,
float& tcoll)
{
// 先找到碰撞 int mini =-1; tcoll =0.0f;
for(int i =0; i < iNumAxes; i ++) {
if(taxis[i]>0.0f) {
if(taxis[i]> tcoll) {
mini = i;
tcoll = taxis[i]; Ncoll = Axis[i]; Ncoll.Normalise();
// 将轴 } } }
// 发现了碰撞
if(mini !=-1)
returntrue; // 不,找到重叠 mini =-1;
for(int i =0; i < iNumAxes; i ++) {
float n = Axis[i].Normalise(); // 轴线长度 taxis[i]/= n;