6 각형 그리드에서 최단 경로 찾기


14

시뮬레이션 요소가있는 턴 기반 게임을 작성 중입니다. 내가 지금 끊고있는 한 가지 일은 경로 찾기입니다. 내가하고 싶은 것은 AI 모험가를 현재 x, y와 대상 x, y를 사용하여 대상에 한 타일 더 가깝게 움직입니다.

이것을 스스로 알아 내려고 노력하면서 4 방향을 사용하여 문제가 없음을 결정할 수 있습니다.

dx = currentX - targetY
dy = currentY - targetY

그러나 6 가지 방향 중 어느 것이 실제로 "최고"또는 "최단"경로인지 결정하는 방법을 잘 모르겠습니다.

예를 들어, 현재 설정 방식은 East, West, NE, NW, SE, SW를 사용하지만 NE 타일에 도달하려면 NW를 이동하는 대신 East를 NW로 이동하십시오.

나는 이것이 모두 엉망이 아니기를 바랍니다. 나를 시작하는 링크 하나만 있으면 좋을 것입니다. 내가 찾은 정보의 대부분은 그리드를 그리고 필요한 이상한 좌표계를 구상하는 것입니다.


5
A *는 그래프의 모양에 관계없이 당신에게 최단 경로를 제공합니다 (그리드, 육각, 자유 ..)
야리 Komppa에게

답변:


21

몇 가지 답변!

16 진수 순회에서 가장 자주 본 좌표계는 플레이어가 NW 및 SE뿐만 아니라 모든 일반 NSEW 방향으로 이동할 수있는 좌표계입니다. 그런 다음 각 행을 제곱 반 오프셋으로 렌더링합니다. 예를 들어, 위치 (2,7)은 (1,7), (3,7), (2,6), (2,8) 및 이상한 것 (1,6)과 인접한 것으로 간주됩니다. (3,8). 한편, 화면 중앙에 (2,7)이 렌더링되었다고 가정하면 (2,6)은 오른쪽에서 오른쪽으로, (2,8)은 왼쪽에서 오른쪽으로 렌더링됩니다. -왼쪽, (1,7) 및 (3,7)은 각각 왼쪽과 오른쪽에 괄호로 묶고 (1,6)과 (3,8)은 각각 왼쪽 상단과 오른쪽 하단에 배치합니다.

내가 의미하는 것의 다이어그램 :

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

이렇게하면 가장 짧은 직접 경로를 찾는 것이 어렵지 않습니다. 기수 축을 따라 대상을 오버 슈트하지 않고 가능한 최대 NW / SE 거리를 이동 한 다음 해당 축을 따라 대상으로 직접 이동하십시오.

그러나 물론 그것은 산이나 다른 통과 할 수없는 지형을 통해 행복하게 당신을 안내합니다. 아직 묻지 않은 질문에 대답하려면 : A * 검색 알고리즘 은 길 찾기에 대한 일반적이고 합리적으로 좋은 방법입니다. 그것은 그리드가 아닌 이상한 레이아웃을 처리 할뿐만 아니라 장애물과 심지어 장애물이 있거나 느린 땅을 행복하게 처리합니다.


A * 검색 알고리즘에 대한 링크에 감사드립니다. 내가 nsew와 nw / se를 통과 할 수 있다고 상상할 수있는 유일한 방법은 기울어 진 16 진수입니다. 머리가 이상해 보인다. 저의 예에 저를 연결할 수 있습니까?
Timothy Mayes

4
렌더링 된 이미지가 내부 구조와 많이 유사하지 않아도됩니다. 내부적으로 NSEW 및 NW / SE를 사용하라고 제안 하지만 그리드 인 것처럼 사용자에게 표시합니다. 원래 답변에 설명도 첨부 :)
ZorbaTHut

2
육각 격자에 대한 흥미로운 표현. 나는 일반적으로 들쭉날쭉 한 패턴을 만들기 때문에 홀수 행과 짝수 행의 인접성은 다릅니다. 이것은 경로 검색에 최소한의 복잡성을 추가로 도입하지만 2 차원 배열을보다 효율적으로 사용합니다 (전체 재생 영역을 직사각형으로 가정)
Panda Pajama

2
@PandaPajama : 들쭉날쭉 한 모양은 사각형 맵을 효율적으로 저장하기 위해 더 잘 작동합니다. 이 트릭
amitp at

2
@PandaPajama, 당신이 사용할 수있는 또 다른 흥미로운 트릭이 있습니다. 좌표에 들쭉날쭉하지 않은 표현을 사용한 다음 "들쭉날쭉 한"방법을 사용하는 무언가 뒤에 데이터 저장 공간을 추상화 할 수 있습니다. 들쭉날쭉하지 않은 좌표 시스템이 다루기가 훨씬 쉽다는 것을 알았습니다. 물론 일단 추상화되면 백엔드는 효율적으로 작업하기 위해 원하는 모든 작업을 수행 할 수 있습니다.)
ZorbaTHut

5

방금 CodePlex.com에 16 진수 그리드 유틸리티 라이브러리를 게시했습니다 : https://hexgridutilities.codeplex.com/ 라이브러리에는 경로 찾기 (A * a la Eric Lippert 사용)와 자동 변환을위한 유틸리티가 포함되어 있습니다 들쭉날쭉 한 (사용자라고 함) 좌표 및 들쭉날쭉하지 않은 (정식) 좌표. path-findingn 알고리즘을 사용하면 각 노드의 단계 비용이 16 진 입력 및 6 진 6 진 측에 따라 다를 수 있습니다 (제공된 예제는 더 단순하지만). 또한 섀도우 캐스팅을 사용한 향상된 FOV (Field of Field)가 제공됩니다 [편집 : 단어 제거].

다음은 3 개의 16 진-그리드 좌표계 사이를 쉽게 변환하는 코드 샘플입니다.

static readonly IntMatrix2D MatrixUserToCanon = new IntMatrix2D(2,1, 0,2, 0,0, 2);
IntVector2D VectorCanon {
  get { return !isCanonNull ? vectorCanon : VectorUser * MatrixUserToCanon / 2; }
  set { vectorCanon = value;  isUserNull = isCustomNull = true; }
} IntVector2D vectorCanon;
bool isCanonNull;

static readonly IntMatrix2D MatrixCanonToUser  = new IntMatrix2D(2,-1, 0,2, 0,1, 2);    
IntVector2D VectorUser {
  get { return !isUserNull  ? vectorUser 
             : !isCanonNull ? VectorCanon  * MatrixCanonToUser / 2
                            : VectorCustom * MatrixCustomToUser / 2; }
  set { vectorUser  = value;  isCustomNull = isCanonNull = true; }
} IntVector2D vectorUser;
bool isUserNull;

static IntMatrix2D MatrixCustomToUser = new IntMatrix2D(2,0, 0,-2, 0,(2*Height)-1, 2);
static IntMatrix2D MatrixUserToCustom = new IntMatrix2D(2,0, 0,-2, 0,(2*Height)-1, 2);
IntVector2D VectorCustom {
  get { return !isCustomNull ? vectorCustom : VectorUser * MatrixUserToCustom / 2; }
  set { vectorCustom  = value;  isCanonNull = isUserNull = true; }
} IntVector2D vectorCustom;
bool isCustomNull;

IntMatrix2D 및 IntVector2D는 affine2D Graphics Vector 및 Matrix의 [edit : homogeneous] 정수 구현입니다. 벡터 응용 프로그램에서 2 로의 마지막 나누기는 벡터를 다시 정규화하는 것입니다. 이것은 IntMatrix2D 구현에 묻힐 수 있지만 IntMatrix2D 생성자에 대한 일곱 번째 인수의 이유는 분명하지 않습니다. 비전 류 제형의 캐싱 및 지연 평가의 결합에 주목하십시오.

이 행렬은 다음과 같습니다.

  • 육각 곡물 수직;
  • 표준 좌표 및 사용자 좌표의 경우 왼쪽 위 원점, 사용자 지정 좌표의 경우 왼쪽 아래 원점;
  • Y 축 수직 아래로;
  • 가로로 가로 질러 직사각형 X 축; 과
  • 북동쪽으로의 정식 X 축 (예 : Y 축에서 120도 CCW).

위에서 언급 한 코드 라이브러리는 16 진 선택 (마우스 클릭으로 선택한 16 진 식별)에 대해 유사하게 우아한 메커니즘을 제공합니다.

정규 좌표에서 6 개의 기본 방향 벡터는 들쭉날쭉 한 좌표의 비대칭없이 (1,0), (0,1), (1,1) 및 모든 육각형에 대한 역수입니다.


와! OP가 제기 한 질문 / 문제에 대한 답변을 제공하는 예제 및 문서와 함께 작업 코드 라이브러리를 게시 한 것에 대해 하나의 투표를하십시오.
Pieter Geerkens 2013

5
내가 downvoter가 아니었지만 에티켓은 일반적으로 downvote를 설명하는 의견을 남길 것을 제안합니다. 링크는 부패하는 경향이 있고 SE 사이트는 자체적으로 포함되기 때문에 링크의 측면은 일반적으로 눈살을 찌푸립니다. 여기에 제공된 정보는 흥미롭지 만 사용자의 질문에 대한 답변은 아니며 해당 질문에 대한 답변을 제공 할 수있는 유일한 정보는 링크의 다른쪽에 있습니다.
Steven Stadnicki

좋은 포인트; 감사합니다. 여러 16 진수 그리드 좌표를 효율적으로 유지 관리하는 방법에 대한 질문을 발췌하여 게시물을 확장했습니다. 게시 된 코드 라이브러리는 프리웨어입니다
피터 Geerkens

죄송합니다! 2 분주은 단지 양의 정수 fo를 작동합니다. (다시 감사합니다, K & R.) IntVector2D에서 Normalize () 메서드 호출로 대체되어야합니다.
Pieter Geerkens

public IntVector2D Normalize() { if (Z==1) return this; else { var x = (X >= 0) ? X : X - Z; var y = (Y >= 0) ? Y : Y - Z; return new IntVector2D(x/Z, y/Z); } }
Pieter Geerkens 2013

0

이 문제를 해결하기위한 많은 문헌과 함께 해결 된 문제입니다. 내가 아는 가장 좋은 리소스는 Red Blob Games : https://www.redblobgames.com/grids/hexagons/에 있습니다.

간단히 말해서, 가장 잘못된 이유는 잘못된 좌표계로 시작했기 때문입니다. A * 알고리즘을 구현하는 큐브 좌표계를 사용하는 것은 매우 간단합니다. 위 링크에서 라이브 데모를 참조하십시오.

다른 시스템 을 실제로 사용하려면 필요할 때 변환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.