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


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.