六角形グリッド上の最短経路を見つける


14

私はいくつかのシミュレーション要素を持つターンベースのゲームを書いています。現在私がやっていることの1つは、パス検索です。私がやりたいのは、AI冒険者を1ターンごとに、現在のx、yとターゲットx、yを使用して、ターゲットに1タイルずつ近づけることです。

自分でこれを理解しようとすると、4つの方向を問題なく決定できます

dx = currentX - targetY
dy = currentY - targetY

しかし、6つの方向のどれが実際に「最良」または「最短」ルートであるかを判断する方法がわかりません。

たとえば、現在の設定方法では、東、西、NE、NW、SE、SWを使用していますが、NEタイルに到達するには、NWを移動するだけでなく、Eastを移動してからNWを移動します。

私はこれがすべてとりとめのないことを願っています。リンクを1つまたは2つでも使用して、開始できます。私が見つけた情報のほとんどは、グリッドの描画と必要な奇妙な座標系の探索に関するものです。


5
*は、あなたのグラフの形状にかかわらず、あなたに最短経路を与える(グリッド、六角、自由形式...)
ヤリ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)は上下にレンダリングされます-the-left、(1,7)および(3,7)はそれぞれ左と右に括弧で囲み、(1,6)と(3,8)はそれぞれ左上と右下に配置します。

私が意味するものの図:

ここに画像の説明を入力してください

この方法で行う場合、最短の直接経路を見つけることは難しくありません-枢軸に沿ってターゲットをオーバーシュートせずに可能な最大NW / SE距離を移動し、その軸に沿って直接ターゲットに移動します。

しかし、もちろんそれはあなたを山や他の通行不可能な地形をまっすぐに幸福に走らせます。まだ質問していない質問に答えるには、A *検索アルゴリズムが一般的であり、パスファインディングへの合理的なアプローチです。グリッド以外の奇妙なレイアウトを処理するだけでなく、障害物や障害物/スローグラウンドをうまく処理します。


A *検索アルゴリズムへのリンクをありがとう。nsewとnw / seを横断できると想像できる唯一の方法は、傾斜したヘックスです。それは私の頭の中では奇妙に見えます。その例に私をリンクできますか?
ティモシーメイズ

4
レンダリングされた画像は、内部構造にあまり似ている必要はないと言っています。内部的に NSEWとNW / SEを使用することをお勧めしますが、ユーザーはグリッドのように表示します。元の返信に説明図を
添付

2
16進グリッドの興味深い表現。私は通常、ギザギザのパターンを作るので、奇数行と偶数行では隣接関係が異なります。これは、経路探索における追加最小の複雑さを導入するが、より効率的に二次元アレイを使用して(全体プレイエリアを想定すると、長方形である。
パンダパジャマ

2
@PandaPajama:ギザギザは、長方形の地図を効率的に保存するのに適しています。あなたは非ギザギザの座標はとうまく動作させることができ、このトリック
amitp

2
@PandaPajama、使用できる別の興味深いトリックがあります-ギザギザでない表現を座標に使用し、「ギザギザ」メソッドを使用するものの背後にあるデータストレージのバッキングを抽象化できます。私は、ギザギザのない座標系の方がはるかに扱いやすいことを発見しましたが、抽象化されれば、バックエンドは物事を効率的にするために好きなことを何でも行うことができます:)
ZorbaTHut

5

CodePlex.comに16進グリッドユーティリティのライブラリを投稿しました。 https ライブラリには、パス検索(A- * a la Eric Lippertを使用)と、ギザギザ(ユーザーと呼ばれる)座標とギザギザでない(カノニカルと呼ばれる)座標。path-findingnアルゴリズムにより、各ノードのステップコストは、入力された16進および移動した16進側の両方で変化します(ただし、提供されている例は単純です)。また、シャドウキャスティングを使用した高視野角が提供されます[編集:単語の削除]。

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の[編集:同種]整数実装です。ベクトルアプリケーションでの2による最後の除算は、ベクトルを再正規化することです。これはIntMatrix2D実装に埋もれる可能性がありますが、IntMatrix2Dコンストラクターの7番目の引数の理由はそれほど明確ではありません。非現在の製剤のキャッシュと遅延評価の組み合わせに注意してください。

これらのマトリックスは次の場合です。

  • 六角穀物垂直;
  • CanonicalおよびUser座標の場合は左上の原点、カスタム座標の場合は左下の原点。
  • Y軸が垂直に下向き。
  • 水平方向の長方形のX軸。そして
  • 北東への標準的なX軸(つまり、Y軸から120度CCWで上および右)。

上記のコードライブラリは、16進選択(マウスクリックで選択された16進を識別する)のための同様にエレガントなメカニズムを提供します。

Canonical座標では、6つの基本方向ベクトルは(1,0)、(0,1)、(1,1)およびすべての六角形の逆数であり、ギザギザの座標の非対称性はありません。


うわー!作業コードのライブラリを、例とドキュメントとともに投稿することで、OPによって提起された質問/問題に答えます。
ピーターギアケンズ

5
私はダウンボーターではありませんでしたが(エチケットは一般的にダウンボートを説明するコメントを残すことを提案しています)、ダウンボートは(a)投稿が広告の響きから外れ、(b)回答の大部分を他方に置くためだったと思いますリンクは腐敗する傾向があり、SEサイトは自己完結しようとするため、リンクの側面は一般的に眉をひそめています。ここで提供される情報は興味深いものですが、ユーザーの質問には回答せず、質問に回答できる唯一の情報はリンクの反対側にあります。
スティーブンスタドニッキー

良い点; ありがとうございました。複数の16進グリッド座標を効率的に維持する方法の問題に対処する抜粋で、投稿を拡張しました。投稿されたコードライブラリはフリーウェアです
Pieter Geerkens

おっとっと!2分周は、正の整数だけfoは動作します。:(。、再びK&Rをありがとう)それはIntVector2Dでノーマライズ()メソッドの呼び出しによって置き換えられるべきである
ピーター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); } }
ピータージャーケンズ

0

これは解決された問題であり、それを裏付ける多くの文献があります。私が知っている最高のリソースはRed Blob Gamesにあります:https : //www.redblobgames.com/grids/hexagons/

簡単に言えば、最も可能性の高い理由は、間違った座標系で始めたことです。A *アルゴリズムを実装するキューブ座標系の使用は非常に簡単です。上記のリンクでライブデモをご覧ください。

他のシステムを本当に使用したい場合は、必要に応じて変換します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.