此代码可能比您需要的更全面,并且可以根据您的需要进行重构,但它是一个完整的答案,并且可以灵活地与移动边界矩形和移动圆一起使用。
这是一个图形,可以直观地帮助代码正在做什么。红色圆圈与黑色矩形相交。想象两条穿过对角的假想线。如果你知道圆在 2 条线的哪一边,你可以推断出碰撞的边缘。
首先声明类范围私有成员
Rectangle CollisionBoxRect;
Rectangle circleRect;
Dictionary<string, Vector2> corners;
在您移动圆并设置其位置和潜在相交框的位置之后的更新中,它会进行基本检查以查看圆的边界矩形是否与块的边界矩形有关。如果是这样,它会根据圆与矩形的哪一侧相撞,以适当的碰撞法线改变球的速度。
if (CollisionBoxRect.Intersects(circleRect))
{
ballVelocity = Vector2.Reflect(ballVelocity, GetCollisionNormal(CollisionBoxRect));
}
以下方法支持获取正确的一面(实际上是正常的)。其中一些方法可以在初始化阶段完成一次,如果它们永远不会改变(如 get corners 方法);
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);
}