마우스로 클릭 한 지점으로 범선을 옮기려고합니다. 이 움직임은 현실적이어야한다. (선이 움직이는 뒤쪽에서 노를 젓는 것) 마우스 클릭이 왼쪽에 있고 선박의 앞쪽에서 선박은 올바른 회전을하기 위해 곡선으로 이동해야한다.
마우스로 클릭 한 지점으로 범선을 옮기려고합니다. 이 움직임은 현실적이어야한다. (선이 움직이는 뒤쪽에서 노를 젓는 것) 마우스 클릭이 왼쪽에 있고 선박의 앞쪽에서 선박은 올바른 회전을하기 위해 곡선으로 이동해야한다.
답변:
보기 이 페이지를
현실적인 회전 추가
다음 단계는 우리 유닛에 현실적인 곡선 회전을 추가하여 회전해야 할 때마다 갑자기 방향을 바꾸지 않는 것입니다. 간단한 해결책은 스플라인을 사용하여 갑작스러운 모서리를 회전으로 부드럽게하는 것입니다. 이것은 미학적 관심사 중 일부를 해결하지만 여전히 대부분의 부대에서 물리적으로 매우 비현실적인 움직임을 초래합니다. 예를 들어, 탱크의 급격한 코너링을 타이트한 커브로 변경할 수 있지만 커브 턴은 탱크가 실제로 수행 할 수있는 것보다 훨씬 더 타이트합니다.
더 나은 해결책을 위해, 우리가 알아야 할 첫 번째 것은 우리 장치의 회전 반경입니다. 회전 반경은 매우 간단한 개념입니다. 자동차의 큰 주차장에 있고 바퀴를 왼쪽으로 돌리고 원을 그리며 진행하면 원의 반경은 회전입니다. 반지름. 폭스 바겐 비틀의 회전 반경은 큰 SUV의 회전 반경보다 작을 것이며, 사람의 회전 반경은 큰 벌목 곰의 회전 반경보다 실질적으로 작을 것입니다.
그림 5와 같이 특정 지점 (원점)에 있고 특정 방향으로 향하고 있고 다른 지점 (목적지)에 도달해야한다고 가정 해 보겠습니다. 목적지를 직접 향한 다음 앞으로 나아갈 때까지, 또는 우회전하여 같은 일을하면서 원을 그리며 돌 수 있습니다.
그림 5에서 가장 짧은 경로는 분명히 하단의 녹색 선입니다. 이 경로는 그림 6과 같이 일부 기하학적 관계로 인해 계산하기가 매우 간단합니다.
먼저 우리는 회전 원의 중심 인 점 P의 위치를 계산하고 항상 시작점에서 반경 r을 가리 킵니다. 초기 방향에서 우회전하면 P가 원점에서 (initial_direction-90)의 각도에 있음을 의미합니다.
angleToP = initial_direction - 90 P.x = Origin.x + r * cos(angleToP) P.y = Origin.y + r * sin(angleToP)
이제 중심점 P의 위치를 알았으므로 다이어그램에서 h로 표시된 P에서 대상까지의 거리를 계산할 수 있습니다.
dx = Destination.x - P.x dy = Destination.y - P.y h = sqrt(dx*dx + dy*dy)
이 시점에서 목적지가 원 안에 있지 않은지 확인하고 싶습니다.
if (h < r) return false
이제 직각 삼각형의 다른 두 변의 길이, 즉 h와 r을 알고 있기 때문에 세그먼트 d의 길이를 계산할 수 있습니다. 직각 관계에서 각도를 결정할 수도 있습니다.
d = sqrt(h*h - r*r) theta = arccos(r / h)
마지막으로 원을 떠나 직선에서 시작할 점 Q를 알아 내려면 총 각도 +를 알아야하며 P에서 대상까지의 각도로 쉽게 결정됩니다.
phi = arctan(dy / dx) [offset to the correct quadrant] Q.x = P.x + r * cos(phi + theta) Q.y = P.y + r * sin(phi + theta)
위의 계산은 우회전 경로를 나타냅니다. angleToP를 계산하기 위해 initial_direction에 90을 추가하고 나중에 + 대신-를 사용한다는 점을 제외하고 왼쪽 경로는 정확히 같은 방식으로 계산할 수 있습니다. 두 가지를 모두 계산 한 후에는 경로가 더 짧은 것을보고 해당 경로를 사용합니다.
이 알고리즘과 다음 알고리즘을 구현할 때, 우리는 최대 4 개의 서로 다른 "선 세그먼트"를 저장하는 데이터 구조를 사용합니다. 각 세그먼트는 직선 또는 곡선입니다. 여기에 설명 된 곡선 경로에는 두 개의 선분 만 사용됩니다 : 호와 직선. 데이터 구조에는 선분이 호인지 직선인지, 선분의 길이 및 시작 위치를 지정하는 멤버가 포함됩니다. 세그먼트가 직선 인 경우 데이터 구조는 각도를 지정합니다. 호의 경우 원의 중심, 원의 시작 각도 및 호로 덮인 총 라디안을 지정합니다.
두 지점 사이를 이동하는 데 필요한 곡선 경로를 계산하면 목록 2와 같이 특정 시점에 위치와 방향을 쉽게 계산할 수 있습니다.
리스팅 2. 특정 시간에서의 위치 및 방향 계산.
distance = unit_speed * elapsed_time loop i = 0 to 3: if (distance < LineSegment[i].length) // Unit is somewhere on this line segment if LineSegment[i] is an arc //determine current angle on arc (theta) by adding or //subtracting (distance / r) to the starting angle //depending on whether turning to the left or right position.x = LineSegment[i].center.x + r*cos(theta) position.y = LineSegment[i].center.y + r*sin(theta) //determine current direction (direction) by adding or //subtracting 90 to theta, depending on left/right else position.x = LineSegment[i].start.x + distance * cos(LineSegment[i].line_angle) position.y = LineSegment[i].start.y + distance * sin(LineSegment[i].line_angle) direction = theta break out of loop else distance = distance - LineSegment[i].length
간단한 해결책으로, 이미 언급 했듯이이 aproach를 시도 할 수 있습니다.
선박을 목표 방향으로 향하게하는 단계를 고려하십시오.이 단계에서는 sip에 회전을 적용하지만 앞으로 이동합니다. 선박이 이미 목표를 향하고있는 경우 전진 속도를 적용 할 수 있습니다. 나는 love2d에서 테스트를 준비했다. 여기서는 선박 업데이트 방법을 따른다.
turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
dir = dir.normalize(dir) --normalized
a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
if (a<0) then
a=a+math.pi *2 -- some workaround to have all positive values
end
if a > 0.05 then -- if angle difference
if a < math.pi then
--turn right
self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
else
--turn left
self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
end
--apply turnForwordSpeed
self.x = self.x+ self.forward.x * turnForwordSpeed * dt
self.y = self.y+ self.forward.y * turnForwordSpeed * dt
else
--applly ForwordSpeed
self.x = self.x+ self.forward.x * ForwordSpeed * dt
self.y = self.y+ self.forward.y * ForwordSpeed * dt
end
end
예제 애니메이션은 선회 속도와 전진 속도의 조합이 선회 반경을 너무 크게 정의하기 때문에 선박이 목표에 도달 할 수없는 경우 (최종 루프)를 보여줍니다.이 경우 " turnForwordSpeed
"를 줄이거 나 유용 하게 만들 수 있습니다 각도 거리 ( a
) 및 목표 거리 에 따라 다릅니다 .
Unity Nav 메쉬 시스템은 내비 에이전트 값으로 약간의 장난으로 원하는 것을 할 수 있습니다.
Nav Mesh는 사용이 매우 간단합니다. 하향식 설정에서만 사용 가능 (또는 최소한 x / z 이동에만 사용 가능)
기본적으로 모든 모양 메쉬를 사용하여 탐색 영역을 굽고 탐색 에이전트를 객체에 추가하고 탐색 메쉬 주위의 경로를 찾도록 할 수 있습니다