답변:
이것은 다른 질문을 기반으로하기 때문에 사각형이 축 정렬 될 때 해결책을 줄 것입니다.
먼저 다음 값을 사용하여 현재 객체의 사각형을 만듭니다.
int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;
다음으로, 오래된 객체의 위치 (각 객체에 저장하거나 단순히 함수에 전달할 수있는)가 있어야 기존 객체의 사각형을 생성 할 수 있습니다 (충돌하지 않은 경우).
int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;
이제 충돌의 위치를 알려면 충돌 위치에 이전 위치가 없었던 위치와 새 위치가있는 쪽을 찾아야합니다. 생각할 때 충돌 할 때 발생하는 현상입니다. 충돌하지 않은면이 다른 사각형에 들어갑니다.
이를 수행하는 방법은 다음과 같습니다 (이 함수는 충돌이 있다고 가정합니다. 충돌이없는 경우 호출하지 않아야 함).
bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}
반복하고 반복하십시오.
bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}
bool collidedFromTop(Object otherObj)
{
return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}
bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}
이제 다른 질문의 충돌 응답과 실제로 사용하려면 다음을 수행하십시오.
if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;
다시 말하지만, 이것이 최선의 해결책은 아니지만 충돌 감지를 위해 일반적으로 사용하는 방식입니다.
질문 이이 질문 과 부분적으로 동일하므로 질문 에 대한 답변을 시도하기 위해 답변의 일부를 재사용 할 것입니다.
다음 설명을보다 이해하기 쉽게 컨텍스트와 일부 변수를 정의 할 수 있습니다. 여기서 사용할 표현 형식은 아마도 자신의 데이터 형식과 맞지 않을 수도 있지만이 방법을 이해하는 것이 더 간단해야합니다 (실제로 원리를 이해하면 다른 종류의 표현을 사용하여 다음 방법을 사용할 수 있음)
우리는 Axis Aligned Bounding Box (또는 Oriented Bounded Box )와 움직이는 Entity 를 고려할 것 입니다.
경계 상자는 4면으로 구성되며
각면을 Side1 = [x1, y1, x2, y2] (두 점 [x1, y1] 및 [x2, y2])로 정의합니다.
이동 엔티티는 속도 벡터 (위치 + 속도)로 정의됩니다 :
위치 [posX, posY] 및 속도 [speedX, speedY] .
다음 방법을 사용하여 AABB / OBB의 어느 쪽이 벡터에 닿는 지 확인할 수 있습니다.
1 / AABB의 4면을 통과하는 무한 선과 엔티티 속도 벡터를 경사로 사용하는 엔티티 위치 (사전 충돌)를 통과하는 무한 선 사이의 교차점을 찾습니다. 평행선 또는 겹치는 선에 해당하는 충돌 지점 또는 정의되지 않은 숫자를 찾을 수 있습니다.
2 / 교차점 (있는 경우)을 알고 나면 세그먼트 경계에있는 교차점을 검색 할 수 있습니다.
3 / 마지막으로,리스트에 여전히 여러 점이있는 경우 (속도 벡터가 여러면을 통과 할 수있는 경우) 교차점에서 엔티티 원점까지의 벡터 크기를 사용하여 엔티티 원점에서 가장 가까운 점을 검색 할 수 있습니다.
그런 다음 간단한 내적을 사용하여 충돌 각도를 결정할 수 있습니다.
자세한 내용은:
1 / 교차점 찾기
a / 파라 메트릭 형식 (P (t) = Po + tD)을 사용하여 무한 선 (Ax + Bx = D)을 결정합니다.
포인트 원산지 : 포 = POSX, POSY]
방향 벡터 : D = [speedX 스피디] = Dy가 = 스피디 B = -dx = -speedX D = (Dy를 Po.x *) - (Po.y *의 Dx) = (posX speedY )-(posY speedX) Ax + By = D <====> (speedY x) + (-speedX y) = (posX speedY )-(posY speedX)
엔터티 점 값을 사용하여 방법을 설명했지만이 방법은 경계 상자의 4면 무한 선을 결정하는 방법과 동일합니다 (Po = [x1, y1] 및 D = [x2-x1; y2-y1] 사용). 대신).
b / 다음으로 두 개의 무한 선의 교차점을 찾으려면 다음 시스템을 해결할 수 있습니다.
A1x + B1x = D1 <== 속도 벡터가 경 사진 엔티티 포인트를 통과하는 선.
A2x + B2x = D2 <== AABB 측면을 통과하는 선 중 하나입니다.
가로 채기에 대한 다음 좌표를 산출합니다.
차단 x = (( B 2 * D 1)-( B 1 * D 2)) / (( A 1 * B 2)-( A 2 * B 1))
차단 y = (( A 1 * D 2)- ( A 2 * D 1)) / (( A 1 * B 2)-( A 2 * B 1))
분모 ((A1 * B2)-(A2 * B1))가 0이면 두 선이 평행하거나 겹치므로 교차점이 있어야합니다.
2 / 세그먼트 경계를 테스트합니다. 확인이 간단하므로 자세한 내용이 필요하지 않습니다.
3 / 가장 가까운 지점을 검색합니다. 리스트에 여러 개의 점이 여전히 있으면 어느 쪽이 엔티티 원점에 가장 가까운지를 찾을 수 있습니다.
a / 교점에서 엔티티 원점으로가는 벡터 결정
V = Po-Int = [Po.x-Int.x; 포이-국제]
b / 벡터 크기 계산
|| V || = sqrt (V.x² + V.y²)
4 / 이제 어느 쪽이 칠 것인지를 알았으므로 내적을 사용하여 각도를 결정할 수 있습니다.
a /하자 S = [x2-x1; y2-y1] 은 적중 될 측면 벡터이며 E = [speedX; speedY] 는 엔티티 속도 벡터입니다.
벡터 내적 규칙을 사용하면
S · E = Sx Ex + Sy Ey
및
S · E = || S || || E || cos θ
따라서이 방정식을 약간 조작하여 θ를 결정할 수 있습니다.
cos θ = (S · E) / (|| S || || E ||)
θ = acos ((S · E) / (|| S || || E ||))
와
S · E = Sx * Ex + Sy * Ey
|| S || = sqrt (Sx² + Sy²)
|| E || = sqrt (Ex² + Ey²)
참고 : 다른 질문 스레드에서 말했듯이, 이것은 아마도 가장 효율적이거나 가장 간단한 방법이 아니며, 이것은 생각한 것일 뿐이며 수학의 일부가 도움이 될 수 있습니다.
구체적인 OBB 예제 (AABB로 했음)로는 확인되지 않았지만 작동해야합니다.
간단한 방법은 충돌을 해결 한 다음 움직이는 객체의 충돌 상자를 각 방향으로 한 픽셀 씩 차례로 변환하고 충돌하는 결과를 보는 것입니다.
"적절하게"회전 충돌 모양이나 임의의 다각형을 사용하려면 분리 축 정리를 읽는 것이 좋습니다. 예를 들어 메타넷 소프트웨어 (N 게임을 만든 사람들)는 SAT에 대한 훌륭한 개발자 기사를 가지고 있습니다 . 또한 관련된 물리학에 대해서도 논의합니다.
한 가지 방법은 사각형 주위에서 세계를 회전시키는 것입니다. 이 경우의 "세계"는 여러분이 관심을 갖는 개체, 즉 사각형과 공입니다. 경계가 x- / y- 축과 정렬 될 때까지 중앙을 중심으로 사각형을 회전 한 다음 공을 같은 양만큼 회전시킵니다.
여기서 중요한 점은 공을 직사각형이 아닌 중심 주위로 회전시키는 것입니다.
그런 다음 회전하지 않은 다른 사각형과 마찬가지로 충돌을 쉽게 테스트 할 수 있습니다.
다른 옵션은 사각형을 네 개의 별개의 선 세그먼트로 취급하고 각 사각형과 개별적으로 충돌을 테스트하는 것입니다. 이것은 당신이 충돌을 테스트 할 수 있습니다 및 측면이 동시에 충돌 한 알아낼.
계산에 고정 각도를 사용했지만 일부 도움이 될 것입니다
void Bullet::Ricochet(C_Rect *r)
{
C_Line Line;
//the next two lines are because I detected
// a collision in my main loop so I need to take a step back.
x = x + ceil(speed * ((double)fcos(itofix(angle)) / 65536));
y = y + ceil(speed * ((double)fsin(itofix(angle)) / 65536));
C_Point Prev(x,y);
//the following checks our position to all the lines will give us
// an answer which line we will hit due to no lines
// with angles > 90 lines of a rect always shield the other lines.
Line = r->Get_Closest_Line(Prev);
int langle = 0;
if(!Line.Is_Horizontal()) //we need to rotate the line to a horizontal position
{
langle = Line.Get_Point1().Find_Fixed_Angle(Line.Get_Point2());
angle = angle - langle; //to give us the new angle of approach
}
//at this point the line is horizontal and the bullet is ready to be fixed.
angle = 256 - angle;
angle += langle;
}