- 简介
上一篇完成了碰撞点的初步获取,这回阅读的是碰撞点的第二步获取。 - 碰撞点截取
因为有一定可能使得取得的B上的碰撞点在A的宽度范围之外,这样一来,范围之外的点属于没有意义的点,所以需要根据A的宽度将点截断在A的宽度范围内。 - 代码
/*参数列表:vOut[2]输出结果,vIn[2]输入的碰撞点候选点,normal侧方向上的向量(假设以矩形A坐标系为主)
offset侧方向上的坐标值。
这假设前面是以A坐标系为主,vIn[2]是获取自矩形B上的顶点且已经转换到世界坐标
*/
int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2],
const Vec2& normal, float offset, char clipEdge)
{
int numOut = 0;
// Calculate the distance of end points to the line
//将B的世界坐标vIn转换到A的局部坐标,仅限于sideNormal方向上的坐标值
//这里normal在外面取的是矩阵的列向量,所以下面的计算实际上是原本矩阵中
//某个轴方向上的逆运算,Dot(normal, vIn[0].v)就是算坐标(x,y)中的x或者y
//从世界坐标变换到A坐标系的x或者y,offset实际存放的是A矩形在normal方向
//上的矩形某个端点的x或者y坐标值(投影)。最终distance(0/1)得到的如果是小0的数字
//说明两个点在矩形AsideNormal方向长度的范围内。
float distance0 = Dot(normal, vIn[0].v) - offset;
float distance1 = Dot(normal, vIn[1].v) - offset;
//这里就是直接记录结果
if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
//如果有一个点在范围之外
if (distance0 * distance1 < 0.0f)
{
//这里算出矩形A的端点在两个碰撞点之间的位置
float interp = distance0 / (distance0 - distance1);
//然后求出那个A端点的位置,作为截断
vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
//存储一些相关信息
if (distance0 > 0.0f)
{
vOut[numOut].fp = vIn[0].fp;
vOut[numOut].fp.e.inEdge1 = clipEdge;
vOut[numOut].fp.e.inEdge2 = NO_EDGE;
}
else
{
vOut[numOut].fp = vIn[1].fp;
vOut[numOut].fp.e.outEdge1 = clipEdge;
vOut[numOut].fp.e.outEdge2 = NO_EDGE;
}
++numOut;
}
return numOut;
}
对A的两边的边界分别计算,这样一来,点都会被调整到A的宽度范围内。下面连读两次调用了截断函数。分别是不同的sideNormal方向。
//4.筛选碰撞顶点,计算出合适的碰撞点
//前面已经得到了两个矩形上的顶点,这两个顶点需要再加工一下
//实际上就是将顶点限制在sideNormal方向上的negSide和posSide范围之间
ClipVertex clipPoints1[2];
ClipVertex clipPoints2[2];
int np;//取得的点个数
//clipPoints1此时是结果接收,incidentEdge是前面获得的与碰撞相关的
//矩形顶点,输入sideNormal,这个类似剪裁,当在矩形A坐标系下,incidentEdge中B的
//顶点如果超出了negSide和posSide的范围,就剪裁到范围内,剪裁方向是-sideNormal。
np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, negSide, negEdge);
if (np < 2)
return 0;
//经过上面的剪裁后,现在其基础上剪裁sideNormal方向
np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, posSide, posEdge);
if (np < 2)
return 0;