移动圆与静止圆碰撞检测:求解碰撞交点及Java实现
移动圆与静止圆的碰撞点计算方案与Java实现
数学推导
你列出的方程可以整理为标准二次方程求解参数t,步骤如下:
- 定义辅助向量:
D = S - P:移动圆起点到静止圆圆心的向量V = End - S:移动圆的位移向量
- 展开并整理碰撞条件方程:
原方程(Ra+Rb)² = |P - (S + tV)|²等价于(Ra+Rb)² = |(S - P) + tV|²,展开后得到:
这是标准的|V|² * t² + 2*(D·V)*t + (|D|² - (Ra+Rb)²) = 0a*t² + b*t + c = 0形式,其中:a = V.x² + V.y²b = 2*(D.x*V.x + D.y*V.y)c = (D.x² + D.y²) - (Ra + Rb)*(Ra + Rb)
- 求解二次方程:
- 计算判别式
delta = b² - 4*a*c:- 若
delta < 0:无实根,两圆在移动路径内无碰撞,返回目标点End - 若
delta >= 0:计算两个根t1 = [-b - sqrt(delta)]/(2*a),t2 = [-b + sqrt(delta)]/(2*a)(t1 <= t2)
- 若
- 计算判别式
- 筛选有效
t值:
只有当t在[0,1]区间内时,碰撞点才落在移动圆的起点到终点路径上。取最小的符合条件的t值,计算碰撞点C = S + t*V;若没有符合条件的t,返回目标点End
Java代码实现
首先定义表示点的类:
class Point { public double x; public double y; public Point(double x, double y) { this.x = x; this.y = y; } // 用于计算点的加法与数乘 public Point add(Point other) { return new Point(this.x + other.x, this.y + other.y); } public Point multiply(double scalar) { return new Point(this.x * scalar, this.y * scalar); } }
然后实现核心计算函数:
public class CircleCollision { public static Point calculateCollisionPoint(Point startS, Point end, Point staticP, double ra, double rb) { // 计算位移向量V Point V = new Point(end.x - startS.x, end.y - startS.y); // 计算向量D = S - P Point D = new Point(startS.x - staticP.x, startS.y - staticP.y); double a = V.x * V.x + V.y * V.y; // 若移动向量长度为0(起点等于终点),直接返回起点 if (a == 0) { return startS; } double b = 2 * (D.x * V.x + D.y * V.y); double sumRadii = ra + rb; double c = (D.x * D.x + D.y * D.y) - sumRadii * sumRadii; double delta = b * b - 4 * a * c; // 无实根,无碰撞 if (delta < 0) { return end; } double sqrtDelta = Math.sqrt(delta); double t1 = (-b - sqrtDelta) / (2 * a); double t2 = (-b + sqrtDelta) / (2 * a); // 寻找符合0<=t<=1的最小t double validT = Double.MAX_VALUE; if (t1 >= 0 && t1 <= 1) { validT = t1; } if (t2 >= 0 && t2 <= 1 && t2 < validT) { validT = t2; } // 没有有效t,返回终点 if (validT == Double.MAX_VALUE) { return end; } // 计算碰撞点 return startS.add(V.multiply(validT)); } // 测试示例 public static void main(String[] args) { Point start = new Point(0, 0); Point end = new Point(10, 0); Point staticCircle = new Point(5, 0); double ra = 1; double rb = 1; Point collisionPoint = calculateCollisionPoint(start, end, staticCircle, ra, rb); System.out.println("碰撞点坐标:(" + collisionPoint.x + ", " + collisionPoint.y + ")"); } }
代码说明
- 处理了移动向量为0的特殊情况(起点与终点重合)
- 严格筛选
t的有效范围,确保碰撞点落在移动路径内 - 优先取更小的
t值,保证返回的是靠近起点的碰撞点
内容的提问来源于stack exchange,提问作者MrSquidness
相关产品推荐
相关产品推荐

