前几天写一个j2me的2d俯视视角赛车游戏。赛车用可旋转的矩形作为碰撞体,先用自由矩形的外接矩形做预计碰撞,然后再用分离轴定律实现真正的碰撞。我把起实现代码分享给大家:
/**
* 两个自由矩形的碰撞检测 sat(分离轴定律)方法
*
* @param rectFree_a
* 自由矩形a
* @param rectFree_b
* 自由矩形b
* @return
*/
public static boolean freeRectIsct(RectFree rectFree_a, RectFree rectFree_b) {//这里的RectFree是我自己实现的一个自由旋转矩形
Vector2[] axis_proj = new Vector2[4];// 4个投影轴(这里的vector2是也我自己实现的2维向量,内容很简单)
axis_proj[0] = new Vector2(rectFree_a.ver_d.x - rectFree_a.ver_a.x,
rectFree_a.ver_d.y - rectFree_a.ver_a.y);
axis_proj[1] = new Vector2(rectFree_a.ver_a.x - rectFree_a.ver_b.x,
rectFree_a.ver_a.y - rectFree_a.ver_b.y);
axis_proj[2] = new Vector2(rectFree_b.ver_d.x - rectFree_b.ver_a.x,
rectFree_b.ver_d.y - rectFree_b.ver_a.y);
axis_proj[3] = new Vector2(rectFree_b.ver_a.x - rectFree_b.ver_b.x,
rectFree_b.ver_a.y - rectFree_b.ver_b.y);
// 最大最小的投影标量
float scalar_max_a = 0;
float scalar_min_a = 0;
float scalar_max_b = 0;
float scalar_min_b = 0;
Vector2 v_translate = null;//平移向量(由于没有设置局部坐标,所以需要矩形平移后再对各个顶点进行投影)
for (int i = 0; i < 4; i++) {
if (i == 0)
v_translate = rectFree_a.ver_a;
else if (i == 1)
v_translate = rectFree_a.ver_b;
else if (i == 2)
v_translate = rectFree_b.ver_a;
else
v_translate = rectFree_b.ver_b;
Vector2[] vector_proj_b = new Vector2[4];
//对矩形b的四个顶点投影方法
vector_proj_b[0] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_b.ver_a.add(v_translate.negative()))//negitive()是自己实现的向量的负向量
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_b[1] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_b.ver_b.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_b[2] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_b.ver_c.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_b[3] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_b.ver_d.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
float[] scalar_proj_b = new float[4];// 各个顶点投影的标量值
for (int j = 0; j < 4; j++) {
scalar_proj_b[j] = vector_proj_b[j].dotProduct(axis_proj[i]);//计算投影点的标量值,(与投影轴的点积)
}
scalar_max_b = scalar_proj_b[0];
scalar_min_b = scalar_proj_b[0];
for (int j = 1; j < 4; j++) {//简单的计算标量值的最大值和最小值
if (scalar_proj_b[j] < scalar_min_b)
scalar_min_b = scalar_proj_b[j];
if (scalar_proj_b[j] > scalar_max_b)
scalar_max_b = scalar_proj_b[j];
}
Vector2[] vector_proj_a = new Vector2[4];
//再对矩形a进行同样的计算
vector_proj_a[0] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_a.ver_a.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_a[1] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_a.ver_b.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_a[2] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_a.ver_c.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
vector_proj_a[3] = axis_proj[i].mult(axis_proj[i]
.dotProduct(rectFree_a.ver_d.add(v_translate.negative()))
/ axis_proj[i].dotProduct(axis_proj[i]));
float[] scalar_proj_a = new float[4];
for (int j = 0; j < 4; j++) {
scalar_proj_a[j] = vector_proj_a[j].dotProduct(axis_proj[i]);
}
scalar_max_a = scalar_proj_a[0];
scalar_min_a = scalar_proj_a[0];
for (int j = 1; j < 4; j++) {
if (scalar_proj_a[j] < scalar_min_a)
scalar_min_a = scalar_proj_a[j];
if (scalar_proj_a[j] > scalar_max_a)
scalar_max_a = scalar_proj_a[j];
}
//碰撞判断(分离轴定律,有任何一个轴使两个凸多边形顶点的投影没有出现交错即两个多边形没有相交)
if (scalar_min_a > scalar_max_b || scalar_max_a < scalar_min_b)
return false;
}
return true;
}
分离轴定律不太了解的可以自行百度。