すり抜けない当たり判定
とりあえず載せると言ったので載せる。誰も見ないかな。
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; } }