5.回転させた四角形と回転させた四角形の当たり判定

回転させた四角形と回転させた四角形との判定をやります
横と縦の長さが同じではないので、別途計算が必要になろうかと思います。 まずは、新たに定義する回転する四角形のクラス定義からです。

OrientedRectangle


/**
 * chapter5
 * oriented rectangle class
 *
 * center:原点から四角形の中心へのベクトル
 * halfExtend:中心から四隅へのベクトル
 */
var OrientedRectangle = class OrientedRectangle {
	constructor(center,halfExtend,rotation){
		this.center = center;
		this.halfExtend = halfExtend;
		this.rotation = rotation
	}
}
		

これ図形で表すと

続いて当たり判定の関数です。

回転四角形当たり判定関数


/*
	chapter5
	回転する四角形と四角形の衝突

	r1:OrientedRectangle
	r2:OrientedRectangle

	return boolean

*/
function isOrientedRectangleCollide(r1,r2){
	var edge = getOrientedRectangleEdge(r1,0);

	if(isSeparatingAxisForOrientedRectangle(edge,r2)){
		return false;
	}

	edge = getOrientedRectangleEdge(r1,1);
	if(isSeparatingAxisForOrientedRectangle(edge,r2)){
		return false;
	}

	edge = getOrientedRectangleEdge(r2,0);
	if(isSeparatingAxisForOrientedRectangle(edge,r1)){
		return false;
	}

	edge = getOrientedRectangleEdge(r2,1);
	return !isSeparatingAxisForOrientedRectangle(edge,r1);

}
		

isSeparatingAxisForOrientedRectangle関数によって、
四角形の一辺と四角形の対応する辺が交わるかどうかで判定を行い
これが、四方の辺で交わっていなければ、二つの四角形は交わっていない
交わっていれば、二つの四角形が重なっていると判定しています。 isSeparatingAxisForOrientedRectangle関数に関しては、
のちに図で概念を表します

四角形の一辺を取得する関数

続いて辺の四角形の辺の一辺を得る
getOrientedRectangleEdge関数です


/**
 * chapter5
 *
 *
 */
function getOrientedRectangleEdge(orientedRectangle,point){
	var edge = new LineSegment2D();
	var vecA = orientedRectangle.halfExtend;
	var vecB = orientedRectangle.halfExtend;

	// 右回りで取得する
	// 0,2
	// 1,3は対辺を表す
	switch(point % 4){
	case 0:
		vecA.x = -vecA.x;
		break;
	case 1:
		vecB.y = -vecB.y;
		break;
	case 2:
		vecA.y = -vecA.y;
		vecB = getNegateVector(vecB)
		break;
	case 3:
		vecA = getNegateVector(vecA);
		vecB.x = -vecB.x;
		break;
	}

	vecA = getRotateVector(vecA,orientedRectangle.rotation);
	vecA = getAddVector(vecA,orientedRectangle.center);

	vecB = getRotateVector(vecB,orientedRectangle.rotation);
	vecB = getAddVector(vecB,orientedRectangle.center);

	edge.point1 = vecA;
	edge.point2 = vecB;
	return edge;
}

/**
 * chapter5
 *
 * 逆ベクトルを返す
 */
function getNegateVector(vector){
	vector.x = -vector.x;
	vector.y = -vector.y;
	return vector;
}

/*
	chapter5
	vec:Vector2D

	return Vector2D
*/
function getRotateVector(vec,degree){
	var radian = getDegreeToRadian(degree);

	var sin = Math.sin(radian);
	var cos = Math.cos(radian);

	var r = new Vector2D();
	r.x = vec.x * cos - vec.y * sin;
	r.y = vec.x * sin + vec.y * cos;

	return r;
}

/**
 * chapter5
 * ベクトル加算
 *
 * vecA:Vector2D
 * vecB:Vector2D
 */
function getAddVector(vecA,vecB){
	vecA.x += vecB.x;
	vecA.y += vecB.y;
	return vecA;
}
		

getOrientedRectangleEdge関数は
引数pointで示した、四角形のうちの特定の一辺を返しています。
これは、四角形と四角形の当たり判定を特定の一辺を基準に判定しているので、
必要になります。

続いて、isSeparatingAxisForOrientedRectangle関数

辺の一辺と、四角形の一辺とが重なっているか判定する関数


/*
	chapter5
	axis:Segment2D
	r:OrientedRectangle
*/
function isSeparatingAxisForOrientedRectangle(axis,r){
	var axisRange = new Range2D();
	var r0Range = new Range2D();
	var r2Range = new Range2D();
	var rProjection = new Range2D();

	// Segment
	var rEdge0 = getOrientedRectangleEdge(r,0);
	var rEdge2 = getOrientedRectangleEdge(r,2);

	var n = subtractVector(axis.point1,axis.point2);

	axisRange = getProjectSegment(axis,n);
	r0Range = getProjectSegment(rEdge0,n);
	r2Range = getProjectSegment(rEdge2,n);
	rProjection = getMaxMinRange(r0Range,r2Range);

	return !isOverLappingRanges(axisRange,rProjection);
}

/**
 * chapter5
 * 2つのRangeクラスにおける
 * 最小値と最大値を設定したRangeクラスを返す
 *
 */
function getMaxMinRange(range1,range2){
	var range = new Range();
	range.min = range1.min < range2.min ? range1.min : range2.min;
	range.max = range1.max < range2.max ? range2.max : range1.max;
	return range;
}
		

関数だけみてもなにやってるのかわからんので、図解します

まず、赤い四角形(関数でいう引数のr)対になる2辺rEdge0とrEdge2の頂点
から正射影ベクトルを下ろして、rProjectとします。(正射影ベクトルについては、別記事を確認してください)

rProjectionと本来は四角形の一辺となるaxisが重なっていないとすると
この回転四角形同士はぶつかっていないことになります。

なぜかというと、axisは四角形の一辺であり、対する辺は90°で曲がるため、
正射影ベクトルである、rProjectionと交わることはないからです。

この判定を回転四角形の4辺において適用すれば、当たり判定を行うことができそうですね。

回転四角形と回転四角形の当たり判定のサンプル

今回の当たり判定のサンプルをおいたので、動かしてソースを見て
確認してみてください

このエントリーをはてなブックマークに追加