Collision detection: Line

Time:2020-11-1

Introduction

stayCollision Detection :RectangleThis paper mainly introduces the rectangle related collision detection, and then looks at the situation of the straight line.

The following examples are not checked for compatibility and are recommended to be viewed in the latest chrome browsers.

Line/Point

This isSample page

Line and pointObserve the following figure:

Collision detection: Line

It can be seen from the figure that when a point is on a line, the sum of the distances to the two endpoints is the same as the length of the line. The distance between two points is the same as the Pythagorean theorem used before. Considering the accuracy error of calculation, you can set an error allowable range value, which will feel more natural.

/*

*One endpoint of the (x1, Y1) line

*The other endpoint of the (X2, Y2) line

*Coordinates of (PX, py) detection points

*/

function checkLinePoint({x1,y1,x2,y2,px,py}) {

const d1 = getLen([px,py],[x2,y2]);

const d2 = getLen([px,py],[x2,y2]);

const lineLen = getLen([x1,y1],[x2,y2]);

Const buffer = 0.1; // allowable error range

if (d1+d2 >= lineLen-buffer && d1+d2 <= lineLen+buffer) {

Return true; // collision occurs

} else {

Return false; // no collision

}

}

  

/*

*Calculation of straight line distance between two points by Pythagorean theorem

*One endpoint of point1 line

*The other endpoint of the point2 line

*/

function getLen(point1,point2) {

const [x1,y2] = point1;

const [x2,y2] = point1;

const minusX = x2-x1;

const minusY = y2-y1;

const len = Math.sqrt(minusX*minusX + minusY*minusY);

return len;

}

Line/Circle

This isSample page

Lines and circlesFirst of all, we need to consider whether the line is in the circle, because the length of the line may be smaller than the diameter of the circle. To test this, you can use thePoint/CircleIf any end is inside, it will be returned directlytrueSkip the rest of the tests.


const isInside1 = checkPointCircle({px:x1,py:y1,cx,cy,radius});

const isInside2 = checkPointCircle({px:x2,py:y2,cx,cy,radius});

if (isInside1 || isInside2) {

return true

}

Next, you need to find the point on the line that is closest to the center of the circleDot product of vectorThe coordinates of the nearest point can be calculated. Here is a simple mathematical derivation.

/**

*

*The vector a represents a line

*T coefficient

*Any point on P1

*A point on a non-linear line

*The nearest point on Pt line to P0

*

*PT = P1 + T * A // both p1 and PT are on the straight line, and there is such a relationship coefficient t

*

*(a.x, a.y) * (pt.x-p0.x, pt.y-p0.y) = 0 // vertical vector, dot product 0

*

*(a.x, a.y) * ((P1 + T * a). X-p0.x, (P1 + T * a). Y-p0.y) = 0 // brought in Pt

*

* a.x *(p1.x + t*a.x - p0.x) + a.y *(p1.y + t*a.y - p0.y) = 0

* t*(a.x*a.x + a.y*a.y) = a.x*(p0.x-p1.x)+a.y*(p0.y-p1.y)

* t = (a.x*(p0.x-p1.x)+a.y*(p0.y-p1.y)) / ((a.x*a.x + a.y*a.y))

*

*After the value of coefficient T is obtained, the coordinates of Pt can be obtained by substituting it into the formula at the beginning

*/

However, the obtained point may exist in the direction of the line extension, so it is necessary to determine whether the point is on the provided line segment. At this time, you can use the previous information aboutLine/PointMethods of detection.


const isOnSegment = checkLinePoint({x1,y1,x2,y2, px:closestX,py:closestY});

if (!isOnSegment) return false;

Finally, the distance between the center of the circle and the nearest point on the straight line is calculated, and the radius of the circle is compared to determine whether the collision occurs. The following is the main logic:

/*

*One endpoint of the (x1, Y1) line

*The other endpoint of the (X2, Y2) line

*The coordinates of the center of (PX, py)

*Radius of radius circle

*/

function checkLineCircle({x1,y1,x2,y2,cx,cy,radius}) {

const isInside1 = checkPointCircle({px:x1,py:y1,cx,cy,radius});

const isInside2 = checkPointCircle({px:x2,py:y2,cx,cy,radius});

if (isInside1 || isInside2) {

return true

}

  

const pointVectorX = x1 - x2;

const pointVectorY = y1 - y2;

const t = (pointVectorX*(cx - x1) + pointVectorY*(cy-y1))/(pointVectorX*pointVectorX+pointVectorY*pointVectorY);

const closestX = x1 + t*pointVectorX;

const closestY = y1 + t*pointVectorY;

  

const isOnSegment = checkLinePoint({x1,y1,x2,y2, px:closestX,py:closestY});

if (!isOnSegment) return false;

  

const distX = closestX - cx;

const distY = closestY - cy;

const distance = Math.sqrt( (distX*distX) + (distY*distY) );

  

if (distance <= radius) {

Return true; // collision occurs

} else {

Return false; // no collision

}

}

Line/Line

This isSample page

Straight line and straight lineIn order to detect the collision, mathematical deduction is needed

/**

*

*Two points on line 1 of P1 P2

*A1 represents the vector of line 1

*Coefficient of T1 straight line 1

*

*Two points on line 2 of P3 P4

*A2 represents the vector of line 2

*T2 coefficient of straight line 2

*

* Pa = P1 + t1*A1

* Pb = P3 + t2*A2

*

*At the intersection, PA = Pb

* x1 + t1*(x2-x1) = x3 + t2*(x4-x3)

* y1 + t1*(y2-y1) =y3 + t2*(y4-y3)

*

*The rest is to solve the bivariate linear equation

* t1 = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3))/((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1))

* t2 = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1))

*

*/

After calculating the coefficients of two lines, if the two lines intersect, the conditions must be met:


if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {

return true;

}

return false;

The following is a complete judgment method:

/*

*One endpoint of (x1, Y1) line 1

*The other endpoint of line 1 of (X2, Y2)

*One endpoint of line 2 of (X3, Y3)

*The other end of line 2 of (x4, Y4)

*/

function checkLineLine({x1,y1,x2,y2,x3,y3,x4,y4}) {

const t1 = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));

const t2 = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));

  

if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {

Return true; // collision occurs

} else {

Return false; // no collision

}

}

Line/Rectangle

This isSample page

Line and rectangleCollision detection can be converted to line and rectangle four edge collision detection, using the previous introduction about the collision detectionLine/LineThe detection method is enough.

Collision detection: Line

/*

*One endpoint of the (x1, Y1) line

*The other endpoint of the (X2, Y2) line

*(Rx, ry) rectangular vertex coordinates

*RW rectangle width

*RH rectangle height

*/

function checkLineRectangle({x1,y1,x2,y2,rx,ry,rw,rh}) {

const isLeftCollision = checkLineLine(x1,y1,x2,y2, x3:rx,y3:ry,x4:rx, y4:ry+rh);

const isRightCollision = checkLineLine(x1,y1,x2,y2, x3:rx+rw,y3:ry, x4:rx+rw,y4:ry+rh);

const isTopCollision = checkLineLine(x1,y1,x2,y2, x3:rx,y3:ry, x4:rx+rw,y4:ry);

const isBottomCollision = checkLineLine(x1,y1,x2,y2, x3:rx,y3:ry+rh, x4:rx+rw,y4:ry+rh);

  

if (isLeftCollision || isRightCollision || isTopCollision || isBottomCollision ) {

Return true; // collision occurs

} else {

Return false; // no collision

}

}

reference material