このコードは必要以上に包括的であり、ニーズに合わせてリファクタリングできますが、完全な答えであり、移動する円とともに境界四角形を移動することで柔軟に使用できます。
これは、コードが何をしているかを視覚的に示すためのグラフィックです。赤い円は黒い四角形と交差しています。反対側の角を通る 2 本の架空の線を視覚化します。円が 2 つの線のそれぞれのどちら側にあるかがわかれば、衝突したエッジを推測できます。

最初にクラス スコープのプライベート メンバーを宣言する
Rectangle CollisionBoxRect;
Rectangle circleRect;
Dictionary<string, Vector2> corners;
円を移動してその位置と交差する可能性のあるボックスの位置を設定した後の更新では、円の境界四角形がブロックの境界四角形に関係しているかどうかを確認する基本的なチェックが行われます。その場合、円が衝突した長方形のどちら側に応じて、適切な衝突法線を使用してボールの速度を変更します。
if (CollisionBoxRect.Intersects(circleRect))
{
ballVelocity = Vector2.Reflect(ballVelocity, GetCollisionNormal(CollisionBoxRect));
}
次のメソッドは、適切な側 (実際には法線) の取得をサポートしています。これらのメソッドのいくつかは、(get corners メソッドのように) 変更されない場合、初期化フェーズで 1 回実行できます。
private Vector2 GetCollisionNormal(Rectangle boxBeingIntersected)
{
getCorners(boxBeingIntersected);
bool isAboveAC = isOnUpperSideOfLine(corners["bottomRight"], corners["topLeft"], getBallCenter());
bool isAboveDB = isOnUpperSideOfLine( corners["topRight"], corners["bottomLeft"], getBallCenter());
if (isAboveAC)
{
if (isAboveDB)
{
//top edge has intersected
return -Vector2.UnitY;
}
else
{
//right edge intersected
return Vector2.UnitX;
}
}
else
{
if (isAboveDB)
{
//left edge has intersected
return -Vector2.UnitX;
}
else
{
//bottom edge intersected
return Vector2.UnitY;
}
}
}
public bool isOnUpperSideOfLine(Vector2 corner1, Vector2 oppositeCorner, Vector2 ballCenter)
{
return ((oppositeCorner.X - corner1.X) * (ballCenter.Y - corner1.Y) - (oppositeCorner.Y - corner1.Y) * (ballCenter.X - corner1.X)) > 0;
}
private Vector2 getBallCenter()
{
return new Vector2(circleRect.Location.X + circleRect.Width / 2, circleRect.Location.Y + circleRect.Height / 2);
}
private void getCorners(Rectangle boxToGetFrom)
{
corners.Clear();
Vector2 tl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y);
Vector2 tr = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y);
Vector2 br = new Vector2(boxToGetFrom.X + boxToGetFrom.Width, boxToGetFrom.Y + boxToGetFrom.Height);
Vector2 bl = new Vector2(boxToGetFrom.X, boxToGetFrom.Y + boxToGetFrom.Height);
corners.Add("topLeft", tl);
corners.Add("topRight", tr);
corners.Add("bottomRight", br);
corners.Add("bottomLeft", bl);
}