Menemukan jalur terpendek pada kisi heksagonal

14

Saya sedang menulis permainan berbasis giliran yang memiliki beberapa elemen simulasi. Satu tugas yang saya tutup saat ini adalah dengan menemukan jalan. Yang ingin saya lakukan adalah memindahkan setiap belokan seorang petualang AI satu ubin lebih dekat ke targetnya menggunakan x saat ini, dan targetnya x, y.

Dalam mencoba mencari tahu sendiri, saya dapat menentukan 4 arah tanpa masalah dengan menggunakan

dx = currentX - targetY
dy = currentY - targetY

tapi saya tidak yakin bagaimana menentukan 6 arah mana yang sebenarnya merupakan rute "terbaik" atau "terpendek".

Sebagai contoh, cara setup saat ini, saya menggunakan Timur, Barat, NE, NW, SE, SW tetapi untuk sampai ke ubin NE saya pindah ke Timur kemudian NW daripada hanya memindahkan NW.

Saya harap ini tidak semua bertele-tele. Bahkan hanya satu atau dua tautan untuk memulai saya akan menyenangkan. Sebagian besar info yang saya temukan adalah pada menggambar grid dan menggosok sistem koordinat aneh yang dibutuhkan.

Timothy Mayes
sumber
5
A * memberi Anda lintasan terpendek terlepas dari bentuk grafik Anda (kisi, hex, bentuk bebas ..)
Jari Komppa

Jawaban:

21

Beberapa jawaban!

Sistem koordinat yang paling sering saya lihat untuk traversal berbasis hex adalah sistem di mana pemain dapat bergerak ke setiap arah NSEW normal, serta NW dan SE. Maka Anda hanya membuat setiap baris offset setengah-persegi. Sebagai contoh, lokasi (2,7) dianggap berdekatan dengan (1,7), (3,7), (2,6), (2,8), dan yang aneh: (1,6) dan (3,8). Sementara itu, jika kita mengasumsikan (2,7) ditampilkan di tengah layar, (2,6) akan ditampilkan atas-dan-ke-kanan, (2,8) akan ditampilkan turun-dan-ke -the-left, (1,7) dan (3,7) akan mengurungnya masing-masing ke kiri dan kanan, dan (1,6) dan (3,8) masing-masing akan menempatkan diri mereka atas kiri dan kanan bawah.

Diagram dari apa yang saya maksud:

masukkan deskripsi gambar di sini

Jika Anda melakukannya dengan cara ini, menemukan jalur langsung terpendek tidak sulit - menempuh jarak NW / SE maksimum yang Anda bisa tanpa melampaui target Anda sepanjang sumbu kardinal, kemudian berjalan langsung di sepanjang sumbu itu ke target.

Tapi tentu saja itu akan dengan senang hati membawa Anda langsung melewati pegunungan atau medan yang tidak bisa dilewati. Untuk menjawab pertanyaan yang belum Anda tanyakan: Algoritma Pencarian A * adalah pendekatan umum dan cukup baik untuk merintis jalan. Ini tidak hanya akan menangani tata letak non-grid yang aneh, tetapi juga akan dengan senang hati mengatasi rintangan dan bahkan terhambat / lambat.

ZorbaTHut
sumber
Terima kasih atas tautan ke algoritma pencarian A *. Satu-satunya cara saya bisa membayangkan bisa melintasi nsew dan nw / se adalah hex miring. Yang terlihat aneh di kepalaku. Bisakah Anda menautkan saya ke contoh itu?
Timothy Mayes
4
Saya mengatakan bahwa gambar yang Anda buat tidak harus memiliki banyak kemiripan dengan struktur internal. Saya menyarankan agar secara internal Anda menggunakan NSEW dan NW / SE, tetapi Anda menampilkannya kepada pengguna seolah-olah itu kotak. Melampirkan diagram penjelasan ke balasan asli :)
ZorbaTHut
2
Representasi yang menarik untuk hex grid. Saya biasanya membuat pola bergerigi, sehingga kedekatannya berbeda untuk baris ganjil dan genap. Ini memperkenalkan kompleksitas minimal tambahan dalam pencarian jalur, tetapi menggunakan array bidimensional lebih efisien (seandainya seluruh area bermain adalah persegi panjang.
Panda Pajama
2
@PandaPajama: jagged berfungsi lebih baik untuk menyimpan peta persegi panjang secara efisien; Anda dapat membuat koordinat yang tidak bergerigi bekerja dengan baik dengan trik ini
amitp
2
@ Pandaanda, ada trik menarik lain yang dapat Anda gunakan - Anda dapat menggunakan representasi non-jagged untuk koordinat, lalu abstraksi dukungan untuk penyimpanan data Anda di belakang sesuatu yang menggunakan metode "jagged". Saya telah menemukan sistem koordinat non-bergerigi jauh lebih mudah untuk ditangani, tetapi tentu saja setelah diabstraksi, backend dapat melakukan apa pun yang
diinginkannya
5

Saya baru saja memposting perpustakaan utilisasi hex-grid di CodePlex.com di sini: https://hexgridutilities.codeplex.com/ Perpustakaan mencakup path-finding (menggunakan A- * a la Eric Lippert) dan menyertakan utiliti untuk konversi otomatis antara koordinat jagged (disebut Pengguna) dan koordinat non-jagged (disebut Canonical). Algoritma path-findingn memungkinkan biaya langkah untuk setiap node bervariasi baik dengan entri hex dan te dilalui hex-side (meskipun contoh yang diberikan lebih sederhana). Juga, bidang pandang yang ditingkatkan menggunakan pengecoran bayangan disediakan, [edit: kata-kata dihapus].

Berikut adalah contoh kode yang dapat dikonversi dengan mudah antara tiga sistem koordinat hex-grid:

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 dan IntVector2D adalah [sunting: homogen] implementasi integer dari affine2D Graphics Vector and Matrix. Pembagian akhir oleh 2 pada aplikasi vektor adalah untuk menormalkan kembali vektor; ini bisa dikubur dalam implementasi IntMatrix2D, tetapi kemudian alasan argumen ke-7 ke konstruktor IntMatrix2D kurang jelas. Perhatikan caching gabungan dan evaluasi malas dari formulasi tidak terkini.

Matriks ini untuk kasus ini:

  • Hex butir vertikal;
  • Asal di kiri atas untuk koordinat Canonical & User, kiri bawah untuk Koordinat kustom;
  • Sumbu Y vertikal ke bawah;
  • Sumbu X persegi panjang melintang secara horizontal; dan
  • Sumbu X Canonical ke Utara-Timur (yaitu ke atas dan ke kanan, pada 120 derajat CCW dari sumbu Y).

Pustaka kode yang disebutkan di atas menyediakan mekanisme elegan yang sama untuk pengambilan hex (yaitu mengidentifikasi hex yang dipilih dengan klik mouse).

Dalam koordinat Canonical, 6 vektor arah-kardinal adalah (1,0), (0,1), (1,1) dan terbalik mereka untuk semua segi enam, tanpa asimetri dari coordintes bergerigi.

Pieter Geerkens
sumber
Wow! Bersih satu suara untuk memposting perpustakaan kode kerja, dengan contoh dan dokumentasi, yang menjawab pertanyaan / masalah yang diajukan oleh OP.
Pieter Geerkens
5
Walaupun saya bukan downvoter (dan etiket umumnya menyarankan meninggalkan komentar yang menjelaskan downvote), saya curiga downvote itu karena (a) postingan muncul dari iklan, dan (b) meletakkan sebagian besar jawaban di sisi lain sisi tautan umumnya tidak disukai karena tautan cenderung membusuk dan situs SE berusaha mandiri. Informasi yang disediakan di sini menarik, tetapi tidak menjawab pertanyaan pengguna , dan satu-satunya informasi yang dapat menjawab pertanyaan itu ada di sisi lain tautan.
Steven Stadnicki
Poin bagus; Terima kasih. Saya telah memperluas posting dengan kutipan yang membahas pertanyaan tentang bagaimana menjaga secara efisien beberapa koordinat hex grid. Pustaka kode yang diposting adalah freeware
Pieter Geerkens
Ups! The membagi-by-2 hanya bekerja fo bilangan bulat positif. (Sekali lagi terima kasih, K&R.) Itu harus diganti dengan panggilan ke metode Normalisasi () di IntVector2D:
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
0

Ini adalah masalah yang terpecahkan, dengan banyak literatur untuk mendukungnya. Sumber daya terbaik yang saya tahu ada di Red Blob Games: https://www.redblobgames.com/grids/hexagons/ .

Singkatnya, alasan yang paling mungkin adalah Anda memulai dengan sistem koordinat yang salah. Menggunakan sistem koordinat Cube yang mengimplementasikan algoritma A * cukup sederhana. Lihat demo langsung di tautan di atas.

Jika Anda benar - benar ingin menggunakan beberapa sistem lain, maka konversikan ke dan dari saat diperlukan.

david.pfx
sumber