Math 使用矢量算法与线段碰撞后错误重新定位圆

Math 使用矢量算法与线段碰撞后错误重新定位圆,math,vector,2d,collision-detection,Math,Vector,2d,Collision Detection,在2D游戏中,我试图在一个圆通过一段后重新定位它。以图片为例,我需要重新定位圆,使B成为圆上的切点 我所掌握的资料如下: x、 圆的y 圆的半径 dirx,diry:圆的x,y方向 A和B之间的距离 我要做的是计算点C的坐标,然后计算点B的坐标,然后从AC(半径)中减去向量AB,然后重新定位-BC后面的x,y 算法中存在一些错误,因为在此之后,中心和直线之间的正交距离永远不会与半径完全相同 Len = Sqrt( dirx^2 + diry^2 ) dx = dirx / Len dy =

在2D游戏中,我试图在一个圆通过一段后重新定位它。以图片为例,我需要重新定位圆,使B成为圆上的切点

我所掌握的资料如下:

  • x、 圆的y

  • 圆的半径

  • dirx,diry:圆的x,y方向

  • A和B之间的距离

我要做的是计算点C的坐标,然后计算点B的坐标,然后从AC(半径)中减去向量AB,然后重新定位-BC后面的x,y

算法中存在一些错误,因为在此之后,中心和直线之间的正交距离永远不会与半径完全相同

Len = Sqrt( dirx^2 + diry^2 )
dx = dirx / Len
dy = diry / Len
// these should be coordinates of point C
tangX = x + radius * dx
tangY = y + radius * dy
// these should be coordinates of point B
wrongX = x + distance* dx
wrongY = y + distance* dy
//these should be vector BC
BCx = tangX - wrongX;
BCy = tangY - wrongY;
// now i reposition the center back of BC
x = x - BCx
y = y - BCy
中心重新定位在正确的方向上,但始终不足以匹配距离AC

换言之:
我想移动中心,使B成为圆和直线之间的切点。换言之,让我来解释这个问题:正如你们所看到的,AC的长度等于我的半径。半径是40。在我的日志中,我打印出A和B之间的距离值。以图像为例,这样的距离大约是30,在我的算法之后,我希望AB是40(半径,AC),但它始终是另一个数字,而不是40。如果公式适当,这个问题相对容易解决。这似乎是一个简单的碰撞检测案例,在检测到碰撞后,您试图调整对象的位置。直观的方法是:你有一个事件告诉你你的物体越过了边界。它的最后一个运动矢量是
(dirX,dirY)
,你的对象越过边界,你会得到
增量。你所需要做的就是向后移动你的对象,沿着相同的运动矢量,沿着它越过边界的相同增量

而不是用切点来推理问题,你可以简单地用物体本身的中心坐标来推理。

现在,输入以下参数:

  • x,y
    作为对象中心和
    r
    半径的最后一个坐标
  • (dirX,dirY)
    成为你的运动矢量
  • alpha
    设为运动矢量与x轴的角度(可以从运动矢量本身计算)
  • delta
    为越过边界的距离

问题的解决方案归结为以下几点:


下面是python 2中的一个可执行代码示例,它实现并测试了该解决方案:

从数学导入sin、cos、atan、fabs作为abs、sqrt、pow
从集合导入namedtuple
#实用程序类型和功能
Disk=namedtuple('Disk','x y radius')
MotionVector=namedtuple('MotionVector','x y')
def sqr(d):
返回功率(d,2)
#解决方案的实际实现
def重新定位磁盘(磁盘、增量、运动向量):
#我们首先计算运动矢量与x轴的夹角
alpha=atan(运动矢量y/运动矢量x)
#然后我们计算我们应该应用的位移
#沿着两个轴移动到我们的物体上
dX=cos(α)*δ
dY=sin(alpha)*delta
#我们会更新物体的坐标
返回磁盘(Disk.x-dX,Disk.y-dY,Disk.radius)
#一种测试方法来执行我们的实现
def测试_重新定位_磁盘():
#在假定的位置初始化磁盘
#越过边界
磁盘=磁盘(80、70、40)
#磁盘沿以下运动矢量移动:
运动向量=运动向量(10,-5)
δ=5
更新=重新定位磁盘(磁盘、增量、运动向量)
#现在我们需要计算物体的坐标
#磁盘应该停止在的边界点
alpha=atan(运动矢量y/运动矢量x)
bX=disk.x+(disk.radius-delta)*cos(alpha)
bY=disk.y+(disk.radius-delta)*sin(alpha)
#最后,我们必须断言
#对象到边界的新坐标相等
#半径
距离=sqrt(sqr(更新的.x-bX)+sqr(更新的.y-bY))
打印('到边界的距离:%f'%1距离)
断言绝对值(距离-圆盘半径)<0.01
测试\u重新定位\u磁盘()


附录

我检查了你粘贴的代码,除非我弄错了,否则逻辑上有问题,你正在检查碰撞并计算圆心到相交线的距离。该逻辑的准确实现意味着求解一个二次方程(检查此项以备将来参考),以确定直线是否与圆相交。然后,为了计算距离,你必须根据相交线的方向向量的点积和通过圆心的正交线来解一个方程

下面是一个python代码片段,演示了第一部分(确定直线是否与圆相交),大致按照上面链接中详述的步骤进行操作:

Line=namedtuple('Line','x1 y1 x2 y2')
#用战俘来讨好敌人
def sqr(d):
返回功率(d,2)
#函数来计算直线方程
#在几个人的坐标之外
#要点
定义坐标到仿射(直线):
#y=hx+j
h=(line.y2-line.y1)/(line.x2-line.x1)
j=y1-(h*x1)
返回(h,j)
#函数来计算二次方程
#参数
def计算二次参数(磁盘、行):
(h,j)=坐标到仿射(直线)
(p,q,r)=(disk.x,disk.y,disk.r)
a=sqr(h)+1
b=2*((h*j)-(h*q)-p)
c=sqr(q)-sqr(r)+sqr(p)-(2*(j*q))+sqr(j)
返回(a、b、c)
#作用