Algorithm 移动圆和固定线段之间的二维碰撞
在游戏程序的上下文中,我有一个移动的圆和一个固定的线段。线段可以具有任意大小和方向Algorithm 移动圆和固定线段之间的二维碰撞,algorithm,2d,collision-detection,Algorithm,2d,Collision Detection,在游戏程序的上下文中,我有一个移动的圆和一个固定的线段。线段可以具有任意大小和方向 我知道圆的半径:r 我知道移动前圆的坐标:(xC1,yC1) 我知道移动后圆的坐标:(xC2,yC2) 我知道线段端点的坐标:(xL1,yL1)-(xL2,yL2) 我在计算时遇到困难: 布尔值:如果圆的任何部分在从(xC1,yC1)移动到(xC2,yC2)时碰到线段 如果布尔值为真,则圆与线段相切时圆中心的坐标(x,y) 看这里: 如果计算x或y的平方根下的值为负值,则线段不相交。除此之外,你可以在得
- 我知道圆的半径:r
- 我知道移动前圆的坐标:(xC1,yC1)
- 我知道移动后圆的坐标:(xC2,yC2)
- 我知道线段端点的坐标:(xL1,yL1)-(xL2,yL2)
- 布尔值:如果圆的任何部分在从(xC1,yC1)移动到(xC2,yC2)时碰到线段
- 如果布尔值为真,则圆与线段相切时圆中心的坐标(x,y)
// I'll bet you already have one of these.
public class Vec : Tuple<double, double>
{
public Vec(double item1, double item2) : base(item1, item2) { }
public double Dot(Vec other)
{ return Item1*other.Item1 + Item2*other.Item2; }
public static Vec operator-(Vec first, Vec second)
{ return new Vec(first.Item1 - second.Item1, first.Item2 - second.Item2);}
public static Vec operator+(Vec first, Vec second)
{ return new Vec(first.Item1 + second.Item1, first.Item2 + second.Item2);}
public static Vec operator*(double first, Vec second)
{ return new Vec(first * second.Item1, first * second.Item2);}
public double Length() { return Math.Sqrt(Dot(this)); }
public Vec Normalize() { return (1 / Length()) * this; }
}
public bool IntersectCircle(Vec origin, Vec lineStart,
Vec lineEnd, Vec circle, double radius, out Vec circleWhenHit)
{
circleWhenHit = null;
// find the closest point on the line segment to the center of the circle
var line = lineEnd - lineStart;
var lineLength = line.Length();
var lineNorm = (1/lineLength)*line;
var segmentToCircle = circle - lineStart;
var closestPointOnSegment = segmentToCircle.Dot(line) / lineLength;
// Special cases where the closest point happens to be the end points
Vec closest;
if (closestPointOnSegment < 0) closest = lineStart;
else if (closestPointOnSegment > lineLength) closest = lineEnd;
else closest = lineStart + closestPointOnSegment*lineNorm;
// Find that distance. If it is less than the radius, then we
// are within the circle
var distanceFromClosest = circle - closest;
var distanceFromClosestLength = distanceFromClosest.Length();
if (distanceFromClosestLength > radius) return false;
// So find the distance that places the intersection point right at
// the radius. This is the center of the circle at the time of collision
// and is different than the result from Doswa
var offset = (radius - distanceFromClosestLength) *
((1/distanceFromClosestLength)*distanceFromClosest);
circleWhenHit = circle - offset;
return true;
}
//我敢打赌你已经有一个了。
公共类向量:元组
{
公共Vec(双项1,双项2):基(项1,项2){
公共双点(Vec其他)
{返回Item1*other.Item1+Item2*other.Item2;}
公共静态Vec运算符-(Vec第一,Vec第二)
{返回新的Vec(first.Item1-second.Item1,first.Item2-second.Item2);}
公共静态Vec运算符+(Vec第一,Vec第二)
{返回新的Vec(first.Item1+second.Item1,first.Item2+second.Item2);}
公共静态Vec运算符*(双精度优先,Vec秒)
{返回新的Vec(first*second.Item1,first*second.Item2);}
public double Length(){return Math.Sqrt(Dot(this));}
public Vec Normalize(){return(1/Length())*this;}
}
公共布尔交叉圆(矢量原点、矢量测线起点、,
矢量线端点、矢量圆、双半径、外矢量圆(HENHIT)
{
circleWhenHit=null;
//在线段上找到离圆心最近的点
var line=lineEnd-lineStart;
var lineLength=line.Length();
var lineNorm=(1/行长)*行;
var segmentToCircle=圆-线路起点;
var closestPointOnSegment=段到圆点(线)/线宽;
//最近点恰好是终点的特殊情况
Vec最近;
如果(ClosesPointOnSegment<0)最近=线路开始;
否则,如果(closestPointOnSegment>lineLength)最近=lineEnd;
else closest=线路起点+闭合点分段*线路标准;
//找到那个距离。如果它小于半径,那么我们
//你在圈内吗
var distanceFromClosest=圆-最近;
var distance fromClosestLength=距离fromClosest.Length();
if(distance fromClosestLength>radius)返回false;
//因此,求出交点所在的距离
//半径。这是碰撞时圆的中心
//与Doswa的结果不同
变量偏移=(半径-距离闭合长度)*
((1/距离最短长度)*距离最近长度);
circleWhenHit=圆-偏移;
返回true;
}
我将用伪算法来回答,而不需要任何代码。在我看来,有两种情况下我们可能会返回true,如下图所示:
这里蓝色是你的圆圈,虚线是轨迹线,红线是你的给定线
- 我们建立了一条辅助轨迹线,从和到两个圆的中心。如果此轨迹线与给定线相交-返回true。有关如何计算该交点的信息,请参见
- 在第二种情况下,第一次测试失败了,但不管怎样,当圆圈在轨道上通过时,它们可能会轻推直线。我们需要进行以下施工:
Ha
和Hb
),这样它们从A
和B
开始的长度正好是圆的半径。然后我们检查这些辅助线是否与轨迹线相交。如果是,则返回true。
- 否则返回false
public class Vector
{
double x_ = 0;
double y_ = 0;
double magnitude_ = 1;
public Vector()
{
}
public Vector(double x,double y)
{
x_ = x;
y_ = y;
}
public Vector(Vector other)
{
x_ = other.x_;
y_ = other.y_;
}
public void add(Vector other)
{
x_ += other.x_;
y_ += other.y_;
}
public void scale(double val)
{
x_ *= val;
y_ *= val;
}
public double dot(Vector other)
{
return x_*other.x_+y_*other.y_;
}
public void cross(Vector other)
{
x_ = x_*other.y_ - y_*other.x_;
}
public void unit()
{
magnitude_ = Math.sqrt(x_*x_+y_*y_);
x_/=magnitude_;
y_/=magnitude_;
}
public double distance(Vector at,Vector point)
{
//
// Create a perpendicular vector
//
Vector perp = new Vector();
perp.perpendicular(this);
perp.unit();
Vector offset = new Vector(point.x_ - at.x_,point.y_ - at.y_);
double d = Math.abs(offset.dot(perp));
double m = magnitude();
double t = dot(offset)/(m*m);
if(t < 0)
{
offset.x_ -= at.x_;
offset.y_ -= at.y_;
d = offset.magnitude();
}
if(t > 1)
{
offset.x_ -= at.x_+x_;
offset.y_ -= at.y_+y_;
d = offset.magnitude();
}
return d;
}
private void perpendicular(Vector other)
{
x_ = -other.y_;
y_ = other.x_;
}
public double magnitude()
{
magnitude_ = Math.sqrt(x_*x_+y_*y_);
return magnitude_;
}
}
公共类向量
{
双x=0;
双y=0;
双幅_uu1;
公共向量()
{
}
公共向量(双x,双y)
{
x_uux=x;
y=y;
}
公共媒介(其他媒介)
{
x_uu=其他.x_uu;
y_uu=其他。y_uu;
}
公共无效添加(矢量其他)
{
x_u+=其他.x_3;;
y_u+=其他y_u;
}
公共空隙率(双val)
{
x_*=val;
y*=val;
}
公共双点(矢量其他)
{
返回x*other.x+y*other.y;
}
公共空间交叉(矢量其他)
{
x_ux=x_*other.y_u-y_*other.x;
}
公共voi