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

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

问题描述

在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之间的距离

我正在做的是计算点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为圆和直线之间的切点.换句话说,让我向您解释这个问题:正如您所看到的,交流电的长度等于我的半径.半径为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()



附录

我仔细阅读了您粘贴的代码,除非我没有记错,否则逻辑上存在问题,您可以通过该逻辑检查碰撞并计算从圆心到相交线的距离.正确执行该逻辑意味着要求解二次方程式(请检查此



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天全站免登陆