다른 물체의 원주를 따라 물체를 옮기는 방법?


11

나는 수학에서 너무 아파서 상처를 입었지만, 일부는 케이크 한 조각이어야합니다. 간단한 원형 경로에서 나이 또는 둘레를 따라 다른 물체를 옮기고 싶습니다. 현재 내 게임 알고리즘은 장애물의 가장자리에서 스프라이트를 움직이고 배치하는 방법을 알고 있으며 이제 다양한 조건에 따라 다음 지점이 움직일 때까지 기다립니다.

여기서 수학 문제 는 중심 (cX, cY), 물체 위치 (oX, oY) 및 이동하는 데 필요한 거리 (d)를 알 때 (aX, aY)(bX, bY) 위치 를 얻는 방법입니다.

여기에 이미지 설명을 입력하십시오


1
d직선 거리 입니까 , 아니면 호입니까?
MichaelHouse

픽셀 단위의 선형 거리
Lumis

벡터가 무엇인지, 벡터에 대한 기본 작업에 익숙하십니까?
Patrick Hughes

@ 패트릭 아니, 나는 벡터에 코스를해야 할 것 같아요. 이것은 프레임 별 애니메이션이므로 코드가 빠르고 최적화되어야합니다.
Lumis

답변:


8

(주의 : 여기서는 두 가지 근사법을 사용하고 있습니다. 첫 번째는 d를 호 길이로, 두 번째는 직교 길이로 사용합니다.이 두 근사값은 비교적 작은 d 값에 적합하지만 만족하지는 않습니다. 의견에 명시된 정확한 질문.)

다행히도 이것에 대한 수학은 비교적 간단합니다. 우선, 중심 위치에서 현재 위치까지의 상대 벡터를 찾을 수 있습니다.

deltaX = oX-cX;
deltaY = oY-cY;

이 상대 벡터를 얻은 후에는 길이를 찾아서 작업하는 원의 반경을 알 수 있습니다.

radius = sqrt(deltaX*deltaX+deltaY*deltaY);

또한 상대 벡터에서 cX에서 oX까지의 선이 정확한 각도를 찾을 수 있습니다.

curTheta = atan2(deltaX, deltaY);

이제 상황이 조금 까다로워집니다. 우선, 원의 원주, 즉 각도가 2π 인 호의 '원호 길이'가 2πr임을 이해하십시오. 일반적으로 반지름 r의 원을 따라 각도 측정이 θ 인 호의 호 길이는 θr입니다. 다이어그램에서 d를 호 길이로 사용하고 반지름을 알기 때문에 세타에서 변화를 찾아서 새로운 위치로 이동시킬 수 있습니다.

deltaTheta = d/radius; // treats d as a distance along the arc

d가 선형 거리 여야하는 경우 상황이 조금 더 복잡하지만 다행이 아닙니다. 여기에서 d는 다른 두 변이 각각 원의 반지름 (각각 cX / cY에서 oX / oY 및 aX / aY) 인 이등변 삼각형의 한 변이며,이 이등변 삼각형을 이등분하면 두 개의 직각 삼각형이 생깁니다. 빗변과 같이 한쪽과 반지름으로 d / 2를 가지며; 이것은 우리 각도의 사인 값이 (d / 2) / 반지름이므로 전체 각도는이 값의 두 배에 불과하다는 것을 의미합니다.

deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance

이 공식에서 asin을 꺼내고 2를 취소하면 마지막 공식과 동일합니다. 이것은 sin (x)가 x의 작은 값에 대해 대략 x라는 것입니다. 이는 유용한 근사치입니다.

이제 우리는 단지 더하거나 빼서 새로운 각도를 찾을 수 있습니다.

newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta

새로운 각도를 가지면 기본적인 삼각법을 사용하여 업데이트 된 상대 벡터를 찾을 수 있습니다.

newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);

중심 위치와 상대 벡터에서 목표 지점을 (최종적으로) 찾을 수 있습니다.

aX = cX+newDeltaX;
aY = cY+newDeltaY;

이제이 모든 것들에 대해 알아야 할 몇 가지 경고가 있습니다. 우선,이 수학은 대부분 부동 소수점이며 실제로는 거의 부동 소수점임을 알아야합니다. 이 방법을 사용하여 루프를 업데이트하고 모든 단계에서 정수 값으로 반올림하면 원이 닫히지 않도록하는 것 (루프를 돌 때마다 안쪽으로 또는 바깥쪽으로 나선형으로 돌리는 것)에서 처음 시작하지 않는 것까지 모든 작업을 수행 할 수 있습니다 장소! (d가 너무 작 으면 aX / aY 또는 bX / bY의 둥근 버전이 정확히 시작 위치 oX / oY 인 위치를 발견 할 수 있습니다.) 다른 경우, 특히 시도하려는 작업의 경우 매우 비쌉니다. 하다; 당신이 당신의 캐릭터가 원호 이동 될 것입니다 알고있는 경우 일반적으로, 당신은 전체 아크 사전에 밖으로 계획해야 하지여기에서 가장 비싼 계산을 전면로드하여 비용을 절감 할 수 있으므로 프레임 단위로이를 선택하십시오. 이와 같이 점진적으로 업데이트하려면 비용을 줄이는 또 다른 좋은 방법은 우선 trig를 사용하지 않는 것입니다. d가 작고 정확 해야 할 필요는 없지만 매우 가까우면 길이 d의 벡터를 oX / oY에 추가하고 중심을 향한 벡터에 직교하는 '트릭'을 수행 할 수 있습니다. (dX, dY)에 직교하는 벡터는 (-dY, dX))로 주어진 다음 올바른 길이로 줄입니다. 이 코드를 단계별로 설명하지는 않지만 지금까지 본 내용을 고려하면 이해가 되길 바랍니다. 마지막 단계에서 새 델타 벡터를 암시 적으로 '축소'합니다.

deltaX = oX-cX; deltaY = oY-cY;
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
orthoX = -deltaY*d/radius;
orthoY = deltaX*d/radius;
newDeltaX = deltaX+orthoX; newDeltaY = deltaY+orthoY;
newLength = sqrt(newDeltaX*newDeltaX+newDeltaY*newDeltaY);
aX = cX+newDeltaX*radius/newLength; aY = cY+newDeltaY*radius/newLength;

1
Steven 나는 근사치를 먼저 시도하려고 생각합니다. 이것은 정확한 것보다 자연스럽고 흥미를 느끼는 것이 더 중요한 게임 일뿐입니다. 또한 속도가 중요합니다. 길고 좋은 튜토리얼에 감사드립니다!
Lumis

와우, Steven 당신의 근사치가 꿈처럼 작동하고 있습니다! bX, bY를 얻기 위해 코드를 변경하는 방법을 알려주십시오. 나는 ... 당신의 직교 개념에 아직 분명하지 오전
Lumis

2
확실한! 여러분은 어느 시점에서 벡터 수학을 이해하고 싶을 것입니다. 일단 그렇게하면 이것이 제 2의 천성이 될 것입니다. bX / bY를 얻으려면 '다른 방향으로'가야합니다. 즉, (특수) 직교 벡터를 추가하는 대신 차감하십시오. 위 코드와 관련하여 'newDeltaX = deltaX-orthoX; newDeltaY = deltaY-orthoY; '다음에 newLength와 동일한 계산을 수행 한 다음'bX = cX + newDeltaX radius / newLength; bY = cY + newDeltaY 반경 / newLength; '.
Steven Stadnicki 2016 년

기본적으로이 코드는 newDeltaX / newDeltaY를 bX / bY 방향 (aX / aY 방향 대신)으로 가리킨 다음 aX / aY를 얻는 것처럼 중앙에 맞추고 추가합니다.
Steven Stadnicki 2016 년

9

이미 가지고있는 두면 (하나는 'c'에서 'o'로, 다른 하나는 'o'에서 'a'로)을 사용하여 삼각형을 만들고 세 번째면은 'a'에서 'c'로갑니다. 당신은 'a'가 아직 어디에 있는지 알지 못하고, 지금 당장 요점이 있다고 상상해보십시오. 측면 'd'와 반대되는 각도의 각도를 계산하려면 삼각법이 필요합니다. 변의 길이는 원의 반지름이므로 c <-> o 및 c <a> a입니다.

이 삼각형의 세 변의 길이를 아직 알 수 없으므로 삼각형의 'd'변과 반대되는 각도를 결정할 수 있습니다. 필요한 경우 SSS (side-side-side) 수식이 있습니다. http://www.teacherschoice.com.au/maths_library/trigonometry/solve_trig_sss.htm

SSS 공식을 사용하면 측면 'd'와 반대되는 각도 ( 'j'라고 함)가 있습니다. 이제 (aX, aY)를 계산할 수 있습니다.

// This is the angle from 'c' to 'o'
float angle = Math.atan2(oY - cY, oX - cX)

// Add the angle we calculated earlier.
angle += j;

Vector2 a = new Vector2( radius * Math.cos(angle), radius * Math.sin(angle) );

계산하는 각도가 항상 라디안으로되어 있는지 확인하십시오.

원의 반지름을 계산 해야하는 경우 벡터 빼기를 사용하고 점 'o'에서 점 'c'를 빼고 결과 벡터의 길이를 얻을 수 있습니다.

float lengthSquared = ( inVect.x * inVect.x
                      + inVect.y * inVect.y
                      + inVect.z * inVect.z );

float radius = Math.sqrt(lengthSquared);

이런 식으로해야한다고 생각합니다. Java를 모르므로 정확한 구문을 추측했습니다.

다음은 Byte56이 삼각형 모양을 보여주기 위해 사용자 가 제공 한 이미지입니다 . 카오 삼각형


1
나는 대답을하고 있었지만 이것이 전부입니다. 내가 만든 이미지를 사용하실 수 있습니다. :) i.imgur.com/UUBgM.png
MichaelHouse

@ Byte56 : 감사합니다. 설명 할 이미지 편집기 핸들이 없습니다.
Nic Foster

반경도 계산해야합니다. 이등변 삼각형이 있기 때문에 전체 SSS 계산보다 j를 얻는 더 간단한 방법이 있어야합니다.)
Steven Stadnicki 2016 년

예, 저도 간단 해 보입니다! Android에는 Vector2가 없으므로 값을 별도로 사용할 수 있다고 생각합니다. 엄청나게 나는 안드로이드를 위해 수동으로 만든 Vector2 클래스를 여기에서 발견했다 : code.google.com/p/beginning-android-games-2/source/browse/trunk/…
Lumis

(나는 정확한 선형 거리를 찾기 위해 내 자신의 대답을 조정했습니다. 2 * asin (d / (2 * radius))로 deltaTheta의 두 번째 계산은 j를 찾는 방법입니다.)
Steven Stadnicki

3

obj2를 obj1을 중심으로 회전 시키려면 다음을 시도하십시오.

float angle = 0; //init angle

//call in an update
obj2.x = (obj1.x -= r*cos(angle));
obj2.y = (obj1.y += r*sin(angle));
angle-=0.5;

이것은 처음에 각도를 얻는 방법을 보여주지 않으며 질문과 같은 좌표를 찾는 대신 선회하는 방법을 보여줍니다.
MichaelHouse

1
Lewis, 한 점 주위에서 물체를 공전하는 방법을 보여 주셔서 감사합니다. 유용 할 수도 있습니다.
Lumis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.