当前位置:主页>AS 应用>文章内容
  • 2D多边形碰撞检测和反馈[2](as2.0)
  • 来源:toswf.com 作者:toswf 2008-03-08 【
FlashAs作品发表>>我要投稿 | FlashAs讨论区>>AS论坛
Flash Media Server学习站>>www.FMScn.com


扩展用于碰撞反馈的分离轴的方法:
检测多边形是否碰撞是非常有用处的,但是我们可以做的更多。当多边形交叉后,我希望能够让多边形分离来制止他们交叉。
分隔轴的方法还是要被用到的,通过作一个细微的额外工作。他能够返回他穿刺的深度和方向,并以此来分离它们。一个交叉的深度和方向的结合体也被称为MTD,或者是最小的转换距离。这个最小的向量需要让对象分离来制止他们交叉。
我们可以借助于分离轴来计算MTD。
当对象交叉的时候,我们知道了两个对象的交叉的每个分离轴的间隔距离。沿着这个轴的两个间隔的交叉的量提供了一个推进向量,你需要将其应用于这两个对象来让这些对象的投影来制止他们在这个轴上的交叉。

"推力向量"是一个向量,它的作用是你需要应用到A中以便制止他同B交叉。
很明显,你不能让这个对象沿着一个随机的轴来分离。待选的这些轴中应该选择那个交叉的间隔最小的轴。这个推力向量提供了一个最小的转换的距离。
bool Intersect(Polygon A, Polygon B, Vector MTD)
{
// potential separation axes. they get converted into push
vectors Vector Axis[32];
// max of 16 vertices per polygon
int iNumAxis = 0;
for(J = A.num_vertices–1, I = 0; I < A. num_vertices; J = I, I ++)
{
Vector E = A.vertex[I] – A.vertex[J];
Axis[iNumAxis++] = Vector(-E.y, E.x);

if (AxisSeparatePolygons(N, A, B))
return false;
}
for(J = B. num_vertices–1, I = 0; I < B.num_vertices; J = I, I ++)
{
Vector E = B.vertex[I] – B.vertex[J];
Axis[iNumAxis++] = Vector(-E.y, E.x);

if (AxisSeparatePolygons (N, A, B))
return false;
}

// find the MTD among all the separation vectors
MTD = FindMTD(Axis, iNumAxis);

// makes sure the push vector is pushing A away from B
Vector D = A.Position – B.Position;
if (D dot MTD < 0.0f)
MTD = -MTD;

return true;
}

bool AxisSeparatePolygons(Vector Axis, Polygon A, Polygon B)
{
float mina, maxa;&
float minb, maxb;

CalculateInterval(Axis, A, mina, maxa);&
CalculateInterval(Axis, B, minb, maxb);

if (mina > maxb || minb > maxa)
return true;

// find the interval overlap
float d0 = maxa - minb;
float d1 = maxb - mina;
float depth = (d0 < d1)? d0 : d1;

// convert the separation axis into a push vector (re-normalise
// the axis and multiply by interval overlap)
float axis_length_squared = Axis dot Axis;

Axis *= depth / axis_length_squared;
return false;
}

Vector FindMTD(Vector* PushVectors, int iNumVectors)
{
Vector MTD = PushVector[0];
float mind2 = PushVector[0] dot PushVector[0];
for(int I = 1; I < iNumVectors; I ++)
{
float d2 = PushVector[I] * PushVector[I];
if (d2 < mind2)
{
mind2 = d2;
MTD = PushVector[I];
}
}
return MTD;
}

当对象交叉的情况下,你知道了MTD向量,分离他们就简单了。
A.Postion += MTD * 0.5f;
B.Position -= MTD * 0.5f;

很明显了,如果对象A是静态的,例如是环境的一部分,整个MTD都应用到了B(B.position-=MTD)。
如何来处理快速移动的对象
以上的方法只能处理慢速的对象,但是当对象快速的移动的时候,碰撞会不准确,忽略掉一些碰撞,甚至是允许对象互相穿越,这是一种糟糕的情况。
我们可以再次的使用分离轴的方法,扩展到他的将来,使用这一规则来在未来的某个时间来计算碰撞,原理是一样的,以下的这个图片就是一个很好的解释:

这只不过是一个投影数学。如果间隔是分离的,我们就需要计算一下这两个间隔接触的时间。
比较一下那个"静态"的分离轴的计算方法,有一个额外的轴我们需要测试,这很明显是一个相对于位移向量(速度向量)的轴。
所以对于每个分离轴,有三种选择。
间隔重叠
间隔分离,但是在未来的某个时间会重叠。
间隔分离,但是在未来的某个时间不会重叠或者是碰撞的很晚。
第3个选项的意思是对象不会在这帧上碰撞,分离轴真正的分离里这些对象。在这两个对象之间在这一帧上没有任何的碰撞。
AxisSeparatePolygon()函数返回交叠的量或者碰撞的时间,为了区分这两种情况,当一个交叠被发现的时候,一个负数被返回,如果在将来一个碰撞被检测到了,一个整数被返回的,函数类似下列的函数:
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) return false;

// 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], xOffset, xVel, taxis[iNumAxes], t))
return false;
iNumAxes++;
}

// test separation axes of 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], xOffset, xVel, taxis[iNumAxes], t))
return false;

iNumAxes++;
}

// test separation axes of 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, taxis[iNumAxes], t))
return false;
iNumAxes++;
}

if (!FindMTD(xAxis, taxis, iNumAxes, N, t))
return false;

// make sure the polygons gets pushed away from each other.
if (N * xOffset < 0.0f)
N = -N;

return true;
}

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; // if overlapped, do < 0
float d1 = min1 - max0; // if overlapped, d1 > 0

// separated, test dynamic intervals
if (d0 > 0.0f || d1 > 0.0f)
{
float v = Vel dot N;

// small velocity, so only the overlap test will be relevant.
if (fabs(v) < 0.0000001f)
return false;

float t0 =-d0 / v; // time of impact to d0 reaches 0
float t1 = d1 / v; // time of impact to d0 reaches 1
// sort the times.
if (t0 > t1)
{
float temp = t0;
t0 = t1;
t1 = temp;
}
// take the minimum positive
taxis = (t0 > 0.0f)? t0 : t1;

// intersection time too late or back in time, no collision
if (taxis < 0.0f || taxis > tmax)
return true;

return false;
}
else
{
// overlap. get the interval, as a the smallest of |d0| and |d1|
// return negative number to mark it as an overlap
taxis = (d0 > d1)? d0 : d1;
return false;
}
}


bool FindCollisionPlane (Vector* Axis, float* taxis, int iNumAxes, Vector Ncoll, float tcoll)
{
// find collision first
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(); // normalise axis
}
}
}

// found a collision
if (mini != -1)
return true;

// nope, find overlaps
mini = -1;
for(int i = 0; i < iNumAxes; i ++)
{
float n = Axis[i].Normalise(); // axis length

taxis[i] /= n; // normalise interval overlap too

// remember, those numbers are negative, so take the closest to 0
if (mini == -1 || taxis[i] > tcoll)
{
mini = i;
tcoll = taxis[i];
Ncoll = Axis[i];
}
}

return (mini != -1);
}

这就是全部了,一个检测多边形的碰撞的系统返回一个未来的时间或者是当交叉的时候返回那个碰撞的面。




上一篇:2D多边形碰撞检测和反馈[1](as2.0)   下一篇:保存文本文件到本地(as3.0)
  • 用户名:新注册) 密码: 匿名评论
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
FLASH源文件

Copyright © 2006-2008 flashas.net All Rights Reserved.
网站内容咨询: admin#flashas.net (#为@) 联系QQ:40777822 浙ICP备06033001号
(本网站最佳浏览解析度为1024*768, 建议使用IE 6.0或以上版本浏览器。)