使用矢量算法与线段碰撞后错误的重新定位圆 [英] Wrong repositioning circle after collision with segment with a vector algorithm

查看:19
本文介绍了使用矢量算法与线段碰撞后错误的重新定位圆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In a 2D game, i'm trying to repositionate a circle after it passed through a segment. Taking the picture as example situation, i need to reposition back the circle so that B will become the tangent point on the circle.

我得到的信息是:

  • 圆的x,y

  • x,y of the circle

圆的半径

dirx, diry:圆的 x,y 方向

dirx, diry: Direction of x,y the circle is having

A 和 B 之间的距离

Distance between A and B

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

What i'm doing is to calculate the coordinates of point C, then coordinates of point B, and then subtract vector AB from AC (radius), and repositionate x,y back of -BC.

算法有问题,因为在此之后中心和线之间的正交距离永远不会与半径完全相同.

There is something wrong in the algorithm because after that the orthogonal distance between the center and the line is never exactly like the radius.

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.

The center is repositionated in the correct direction but never enough to match the distance AC.

换句话说:我想移动中心并使 B 成为圆和线之间的切点.让我用换句话说来解释这个问题:正如你所看到的,AC 的长度等于我的半径.半径是 40.在我的日志中,我打印出 A 和 B 之间距离的值.以图像为例,这样的距离大约是 30,在我的算法之后,我希望 AB 是 40(半径,AC)但它总是另一个数字,永远不会是 40

In other words: I want to move the center and make B to be the tangent point between the circle and the line. Let me explain you in other words the problem: as you can see length of AC is equal to my radius. The radius is 40. in my log, i print out the value of the distance between A and B. Taking the image as example such distance would be something like 30, after my algorithm i expect that AB is 40 (the radius, AC) but it's always an other number, never 40

推荐答案

如果表述得当,这个问题相对容易解决.这似乎是碰撞检测的一个简单案例,您试图在检测到碰撞后调整对象的位置.构建它的直观方法是:您有一个事件告诉您您的对象跨越了边界.它的最后一个运动向量是 (dirX, dirY) 并且您将获得 delta 对象越过边界.您需要做的就是将您的对象向后移动,沿着相同的运动向量跨越边界的相同增量.

This issue is relatively easy to solve, if formulated appropriately. It seems a simple case of collision detection, where you're seeking to adjust the object's position after detecting the collision. The intuitive way to frame it is: you have an event telling you your object crossed a boundary. Its last motion vector is (dirX, dirY) and you're given the delta your object crossed beyond the boundary. All you need to do is to move your object backwards, the same delta it crossed beyond the boundary, along the same motion vector.

而不是根据切点来推理问题,您可以简单地根据对象本身的中心坐标来推理.

现在,输入以下参数:

And instead of reasoning about the problem in terms of tangent points, you can simply reason about it in terms of the center coordinates of the object itself.

Now, the following parameters are given input:

  • x, y 是对象中心的最后一个坐标,r 是它的半径
  • (dirX, dirY) 成为你的运动向量
  • alpha 是你的运动向量与 x 轴的角度(你可以从运动向量本身计算它)
  • delta 为越过边界的距离
  • let x, y be the last coordinates of your object's center and r its radius
  • let (dirX, dirY) be your motion vector
  • let alpha be the angle of your motion vector to the x axis (you can compute it from the motion vector itself)
  • let delta be the distance crossed beyond the boundary


问题的解决方案简化为以下内容:


The problem's resolution reduces to the following:


这是 Python 2 中的一个可执行代码示例,用于实现和测试该解决方案:


And here's an executable code sample in python 2 that implements and tests that solution:

from math import sin, cos, atan, fabs as abs, sqrt, pow
from collections import namedtuple

# utility types and functions
Disk = namedtuple('Disk', 'x y radius')
MotionVector = namedtuple('MotionVector', 'x y')

def sqr(d):
    return pow(d, 2)


# the actual implementation of the solution
def reposition_disk(disk, delta, motion_vector):
    # we start by computing the angle to the x axis of the motion vector
    alpha = atan(motion_vector.y / motion_vector.x)

    # then we compute the displacement we should apply
    # to our object along both axes

    dX = cos(alpha) * delta
    dY = sin(alpha) * delta

    # and we update the object's coordinates
    return Disk(disk.x - dX, disk.y - dY, disk.radius)


# a test method to exercise our implementation
def test_reposition_disk():
    # initialiasing our disk at a position where it is supposed
    # to have crossed a boundary
    disk = Disk(80, 70, 40)

    # the disk was moving along the following motion vector:
    motion_vector = MotionVector(10, -5)

    delta = 5

    updated = reposition_disk(disk, delta, motion_vector)

    # now we need to compute the coordinates of the 
    # point of the boundary the disk should have stopped at

    alpha = atan(motion_vector.y / motion_vector.x)
    bX = disk.x + (disk.radius - delta) * cos(alpha)
    bY = disk.y + (disk.radius - delta) * sin(alpha)

    # and finally we have to assert that the distance from
    # the object's new coordinates to the boundary is equal
    # to its radius

    distance = sqrt(sqr(updated.x - bX ) + sqr(updated.y - bY))
    print('Distance to boundary : %f' % distance)
    assert abs(distance - disk.radius) < 0.01


test_reposition_disk()



附录

我查看了您粘贴的代码,除非我弄错了,否则逻辑有问题,您正在检查碰撞并计算从圆心到相交线的距离.该逻辑的准确实现意味着求解二次方程(检查这个 link 以供将来参考)以找出线是否与圆相交.然后要计算距离,您必须根据相交线的方向向量和通过圆心的正交线的点积来求解方程.



Addendum

I went through the code you pasted and unless I am mistaken, there is a problem with the logic through which, you are checking for collision and computing the distance from the center of the circle to the intersecting line. An accurate implementation of that logic implies solving a quadratic equation (check this link for future reference) to find out whether the line intersects the circle. Then to compute the distance you'll have to solve an equation based on the dot product of the direction vector of the intersecting line, and the orthogonal line passing through the center of the circle.

这是一个 Python 代码片段,说明了第一部分(确定线是否与圆相交)并大致遵循上述链接中详述的步骤:

Here's a python snippet illustrating the first part (figuring out whether or not the line intersects the circle) and loosely following the steps detailed in the above link:

Line = namedtuple('Line', 'x1 y1 x2 y2')

# currying the square out of pow
def sqr(d):
    return pow(d, 2)


# function to compute the line equation
# out of the coordinates of a couple of
# points
def coords_to_affine(line):
    # y = hx + j
    h = (line.y2 - line.y1) / (line.x2 - line.x1)
    j = y1 - (h * x1)
    return (h, j)


# function to compute the quadratic equation
# parameters
def compute_quadratic_params(disk, line):
    (h, j) = coords_to_affine(line)
    (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)
    return (a, b, c)


# function to test whether a given circle
# intersects a line
def disk_intersects_line(a, b, c):
    # true if (b² - 4ac) >= 0
    return (sqr(b) - (4 * a * c)) >= 0

这篇关于使用矢量算法与线段碰撞后错误的重新定位圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆