当前位置: 首页 > 知识库问答 >
问题:

碰撞响应中如何固定圆和矩形重叠?

荣波
2023-03-14

由于在数字世界中几乎不会发生真正的碰撞,我们总会出现“碰撞”的圆圈与矩形重叠的情况。

在与矩形完美碰撞而不重叠的情况下,如何将圆形放回原处?

假设矩形停止(零速度)并对轴。

共有1个答案

闻人博
2023-03-14

多年来一直盯着这个问题,从来没有想出一个完美的解决方案,我终于做到了!

这是一个非常简单的算法,不需要循环和近似。

这是它在更高层次上的工作方式:

    null
    null
float L = bounds.left;
float T = bounds.top;
float R = bounds.right;
float B = bounds.bottom;
float dx = end.x - start.x;
float dy = end.y - start.y;
float ltime = Float.MAX_VALUE;
float rtime = Float.MAX_VALUE;
float ttime = Float.MAX_VALUE;
float btime = Float.MAX_VALUE;

if (start.x - radius < L && end.x + radius > L) {
   ltime = ((L - radius) - start.x) / dx;
}
if (start.x + radius > R && end.x - radius < R) {
   rtime = (start.x - (R + radius)) / -dx;
}
if (start.y - radius < T && end.y + radius > T) {
   ttime = ((T - radius) - start.y) / dy;
}
if (start.y + radius > B && end.y - radius < B) {
   btime = (start.y - (B + radius)) / -dy;
}

现在我们试着看看它是否是一个严格的边交叉点(而不是拐角)。如果碰撞点在侧面,则返回交叉点:

if (ltime >= 0.0f && ltime <= 1.0f) {
   float ly = dy * ltime + start.y;
   if (ly >= T && ly <= B) {
      return new Intersection( dx * ltime + start.x, ly, ltime, -1, 0 );
   }
}
else if (rtime >= 0.0f && rtime <= 1.0f) {
   float ry = dy * rtime + start.y;
   if (ry >= T && ry <= B) {
      return new Intersection( dx * rtime + start.x, ry, rtime, 1, 0 );
   }
}

if (ttime >= 0.0f && ttime <= 1.0f) {
   float tx = dx * ttime + start.x;
   if (tx >= L && tx <= R) {
      return new Intersection( tx, dy * ttime + start.y, ttime, 0, -1 );
   }
}
else if (btime >= 0.0f && btime <= 1.0f) {
   float bx = dx * btime + start.x;
   if (bx >= L && bx <= R) {
      return new Intersection( bx, dy * btime + start.y, btime, 0, 1 );
   }
}

我们已经走了这么远所以我们知道不是没有交叉点,就是和一个拐角相撞了。我们需要确定拐角:

float cornerX = Float.MAX_VALUE;
float cornerY = Float.MAX_VALUE;

if (ltime != Float.MAX_VALUE) {
   cornerX = L;
} else if (rtime != Float.MAX_VALUE) {
   cornerX = R;
}

if (ttime != Float.MAX_VALUE) {
   cornerY = T;
} else if (btime != Float.MAX_VALUE) {
   cornerY = B;
}

// Account for the times where we don't pass over a side but we do hit it's corner
if (cornerX != Float.MAX_VALUE && cornerY == Float.MAX_VALUE) {
   cornerY = (dy > 0.0f ? B : T);
}

if (cornerY != Float.MAX_VALUE && cornerX == Float.MAX_VALUE) {
   cornerX = (dx > 0.0f ? R : L);
}

现在我们有足够的信息来解三角形。这使用了距离公式,找到两个向量之间的角度,和正弦定律(两次):

double inverseRadius = 1.0 / radius;
double lineLength = Math.sqrt( dx * dx + dy * dy );
double cornerdx = cornerX - start.x;
double cornerdy = cornerY - start.y;
double cornerdist = Math.sqrt( cornerdx * cornerdx + cornerdy * cornerdy );
double innerAngle = Math.acos( (cornerdx * dx + cornerdy * dy) / (lineLength * cornerdist) );
double innerAngleSin = Math.sin( innerAngle );
double angle1Sin = innerAngleSin * cornerdist * inverseRadius;

// The angle is too large, there cannot be an intersection
if (Math.abs( angle1Sin ) > 1.0f) {
   return null;
}

double angle1 = Math.PI - Math.asin( angle1Sin );
double angle2 = Math.PI - innerAngle - angle1;
double intersectionDistance = radius * Math.sin( angle2 ) / innerAngleSin;
// Solve for time
float time = (float)(intersectionDistance / lineLength);

// If time is outside the boundaries, return null. This algorithm can 
// return a negative time which indicates the previous intersection. 
if (time > 1.0f || time < 0.0f) {
   return null;
}

// Solve the intersection and normal
float ix = time * dx + start.x;
float iy = time * dy + start.y;
float nx = (float)((ix - cornerX) * inverseRadius);
float ny = (float)((iy - cornerY) * inverseRadius);

return new Intersection( ix, iy, time, nx, ny );
Intersection inter = handleIntersection( bounds, start, end, radius );

if (inter != null) 
{
   // Project Future Position
   float remainingTime = 1.0f - inter.time;
   float dx = end.x - start.x;
   float dy = end.y - start.y;
   float dot = dx * inter.nx + dy * inter.ny;
   float ndx = dx - 2 * dot * inter.nx;
   float ndy = dy - 2 * dot * inter.ny;
   float newx = inter.x + ndx * remainingTime;
   float newy = inter.y + ndy * remainingTime;
   // new circle position = {newx, newy}
 }

编辑:您可以修改这为一个旋转矩形通过使用该矩形的角度取消旋转的矩形与圆的开始和结束点。您将执行交点检查,然后旋转得到的点和法线。

编辑:我修改了pastebin上的代码,如果圆的路径的边界卷不与矩形相交,就提前退出。

 类似资料:
  • 我有一个问题,碰撞检测一个圆和一个矩形。我曾尝试用勾股定理来解决这个问题。但所有查询都不起作用。矩形与圆的矩形包围盒发生碰撞。

  • 我正在编写一个游戏,涉及碰撞的一个移动的圆,由用户控制,和一个移动的矩形,由计算机控制。 完整的代码可以在这里找到:游戏 我在圆和矩形之间的碰撞检测方面遇到了麻烦。当矩形是静态的,碰撞检测工作完美。当圆和矩形的边缘在任一边接触时,程序就会按照它应该的方式进行操作。 这是碰撞检测功能。 谢谢。

  • 我花了数小时寻找解决方案:我正在用libgdx开发一个自上而下的小游戏(可能这与我使用的引擎有关)。现在我必须在我的角色(圆形)和墙(矩形)之间实现碰撞检测。如果可以滑动,我希望角色在碰撞时沿着墙滑动。让我解释一下: 如果我向上移动45度,我可能会撞到墙的下面、左边或角落。 如果我与左边相撞,我想停止x运动,只向上移动。如果我离开墙壁,那么我想继续向上移动。与下侧相同(停止y运动) 如果我与角落相

  • 我使用libgdx为一个项目制作了一个2D游戏,我的碰撞检测技术基于。在矩形中重叠方法,效果良好。我想了解其背后的实现,如果我要将其与intersects方法并行,我知道它是如何工作的。但这是唯一的吗?我读到,在离散碰撞检测方法中,不仅需要计算实体是否发生碰撞,还需要计算它们发生碰撞的“程度”(碰撞深度),并使用轴对齐的边界盒算法将实体推回。首先,我对矩形重叠技术是否与libgdx中的AAAB相同

  • 因此,我创建了一个方法来检测球形球和矩形球之间的碰撞。我把它分成了4部分;它检测圆的顶部、圆的左侧、圆的底部、圆的右侧和矩形之间的碰撞。其中的两个工作是检测圆上的左点和矩形之间的碰撞,以及检测圆上的右点和矩形之间的碰撞。但是,不起作用的是,如果最上面的点或最下面的点接触矩形,就不会检测到碰撞,正如我记录if语句以查看是否输入它时所看到的那样。下面是我的代码(方法。getr()获取圆圈半径): 我已

  • 我一直在尝试在Libgdx中找到/创建矩形的碰撞检测,但似乎什么都做不到。我有一个叫bucket的矩形,宽度和高度为64,还有一个叫wall的矩形,宽度和高度为64。我试着让玩家不穿过矩形,可以在粘墙的同时继续移动,而不需要通过相位或随机传送。我的方法在有1个块的情况下有效,但当有多个块的时候,它就会中断,不起作用。 我知道这种方法很难看但这只是实验 如果有人能给我指出正确的方向或分享一些对我有帮