ZerOx4Cの日記だったもの

インポートだけしました

すり抜けない当たり判定

とりあえず載せると言ったので載せる。誰も見ないかな。

Vector deltaVelocity = this.Velocity - opponent.Velocity;
float xtMin, xtMax, ytMin, ytMax, tMin, tMax;

//
// X方向についてのtの範囲を求める。
// 分母deltaVelocityの正負による不等号の判定も考慮している。
//
xtMin = (opponent.Location.X - this.Location.X - this.Size.Width) / deltaVelocity.X;
xtMax = (opponent.Location.X - this.Location.X + opponent.Size.Width) / deltaVelocity.X;
if (deltaVelocity.X < 0) {
	float swap = xtMin;
	xtMin = xtMax;
	xtMax = swap;
}

//
// Y方向についてのtの範囲を求める。
//
ytMin = (opponent.Location.Y - this.Location.Y - this.Size.Height) / deltaVelocity.Y;
ytMax = (opponent.Location.Y - this.Location.Y + opponent.Size.Height) / deltaVelocity.Y;
if (deltaVelocity.Y < 0) {
	float swap = ytMin;
	ytMin = ytMax;
	ytMax = swap;
}

//
// 最小値のみの共通範囲、最大値のみの共通範囲をそれぞれ求める。
//
// 最小値の場合は両者のうち大きい方がより限定された範囲、
// 最大値の場合は両者のうち小さい方がより限定された範囲となる。
//
tMin = Math.Max(xtMin, ytMin);
tMax = Math.Min(xtMax, ytMax);

//
// tMin < tMax : 
//		最小値と最大値に共通範囲が存在するかどうか。
//
// (tMin - 1) * tMax < 0 : 
//		求めた共通範囲が 0 < t < 1 と共通範囲を持つかどうか。
//		これについては求めた共通範囲の取りうる状態全6パターンを図示すると分かるが、
//		最小値 - 1 と最大値の積は 0 < t < 1 と共通範囲を持つとき負になる。
//
if (tMin < tMax && (tMin - 1) * tMax < 0) {
	// 接近限界定数
	const float BARRIER = 0.1f;

	//
	// 自身の親オブジェクトが存在し、かつそれが移動オブジェクトだった場合は、押し戻し処理をする。
	//
	if (this.Parent != null && this.Parent is MovingObject) {
		Vector ownVelocity = (this.Parent as MovingObject).Velocity;
		PointF ownLocation = this.Parent.Location;

		// X方向についての最小値と全体の最小値が一致する場合、
		// X方向には後から接触したことになるので親オブジェクトはX方向に押し戻す必要がある。
		if (tMin == xtMin) {
			// 次の移動で密着するように速度を設定する。
			ownVelocity.X *= tMin;
			// 密着すると次のフレームの初めから接触してしまうので、接近限界定数分だけ座標をずらす。
			ownLocation.X -= Math.Sign(ownVelocity.X) * BARRIER;
		}
		// X方向と同様の押し戻し処理。
		if (tMin == ytMin) {
			ownVelocity.Y *= tMin;
			ownLocation.Y -= Math.Sign(ownVelocity.Y) * BARRIER;
		}

		(this.Parent as MovingObject).Velocity = ownVelocity;
		this.Parent.Location = ownLocation;
	}
	//
	// 相手オブジェクトについての押し戻し処理。
	//
	if (opponent.Parent != null && opponent.Parent is MovingObject) {
		Vector opponentVelocity = (opponent.Parent as MovingObject).Velocity;
		PointF opponentLocation = opponent.Parent.Location;

		// X方向についての押し戻し。
		if (tMin == xtMin) {
			opponentVelocity.X *= tMin;
			opponentLocation.X -= Math.Sign(opponentVelocity.X) * BARRIER;
		}
		// Y方向についての押し戻し。
		if (tMin == ytMin) {
			opponentVelocity.Y *= tMin;
			opponentLocation.Y -= Math.Sign(opponentVelocity.Y) * BARRIER;
		}

		(opponent.Parent as MovingObject).Velocity = opponentVelocity;
		opponent.Parent.Location = opponentLocation;
	}
}