1. 程式人生 > >利用分離軸定律實現的兩個簡單的自由選擇矩形的碰撞

利用分離軸定律實現的兩個簡單的自由選擇矩形的碰撞

前幾天寫一個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;
	}

 分離軸定律不太瞭解的可以自行百度。