Pendahuluan
Ketika mengembangkan game saya, saya sampai pada titik untuk menciptakan NPC pertama. Dan muncul pertanyaan tentang bagaimana membuat NPC berputar-putar dan tidak "masuk ke dalamnya."
Mendaki melalui Internet, saya menemukan algoritma berikut:
- Pencarian Luas (BFS, Pencarian Luas Pertama)
- Algoritma Dijkstra (Dijkstra)
- A Star "A with a asterisk"
- Cari berdasarkan kecocokan terbaik pertama (Pencarian Terlebih Dahulu)
- IDA (A dengan pendalaman berulang)
- Pencarian titik lompat
Dan saya memutuskan untuk mencoba menerapkan A * saya pada kotak 3D voxel.

Contoh peta permainan saya Deskripsi algoritma
A * langkah demi langkah melihat melalui semua jalur yang mengarah dari titik awal ke yang terakhir, sampai menemukan yang minimum. Seperti semua algoritma pencarian yang diinformasikan, ia pertama-tama melihat rute-rute yang “tampaknya” mengarah ke tujuan. Dari algoritma serakah, yang juga merupakan algoritma pencarian untuk kecocokan terbaik pertama, dibedakan oleh fakta bahwa ketika memilih sebuah vertex, ia memperhitungkan, antara lain, seluruh jalur yang dilaluinya.
Visualisasi karya A * di Wikipedia Implementasi
Karena algoritme memerlukan "simpul" - titik untuk menentukan jalur, kami menulis struktur kelas simpul:
Kode Node:public enum EMoveAction { walk, jump, fall, swim }; public class PathPoint {
Konstruktor kelas kecil: private PathPoint NewPathPoint(Vector3 point, float pathLenghtFromStart, float heuristicEstimatePathLenght, EMoveAction moveAction) { PathPoint a = new PathPoint(); a.point = point; a.pathLenghtFromStart = pathLenghtFromStart; a.heuristicEstimatePathLenght = heuristicEstimatePathLenght; a.moveAction = moveAction; return a; } private PathPoint NewPathPoint(Vector3 point, float pathLenghtFromStart, float heuristicEstimatePathLenght, EMoveAction moveAction, PathPoint ppoint) { PathPoint a = new PathPoint(); a.point = point; a.pathLenghtFromStart = pathLenghtFromStart; a.heuristicEstimatePathLenght = heuristicEstimatePathLenght; a.moveAction = moveAction; a.cameFrom = ppoint; return a; }
Selanjutnya, struktur pengaturan pencarian jalur akan berguna:
Kode pengaturan pencarian jalur: public struct SPathFinderType {
Lebih jauh, "Dunia" adalah semacam kelas basis data untuk menyimpan informasi tentang blok peta. Milik Anda dapat diimplementasikan secara berbeda.
Hasil dari fungsi pencarian jalur untuk mendapatkan rute: public List<PathPoint> GetPathToTarget(Vector3 beginPoint, Vector3 targetPoint, World worldData, SPathFinderType pfType) { List<PathPoint> path = new List<PathPoint>();
Closepoint
Fungsi ClosePoint semata-mata tergantung pada implementasi kelas Dunia, itu menambahkan semua jalur yang mungkin ke daftar titik terbuka dari itu dan menghilangkan titik saat ini dari daftar ini (menutupnya). Saya akan memberikan contoh "titik penutup" saya di empat arah pertama.
Peringatan tumpukan kode private List<PathPoint> ClosePoint(int index, List<PathPoint> openPoints, List<PathPoint> closedPoints, World worldData, SPathFinderType pfType, Vector3 targetPoint) { List<PathPoint> newOpenPoints = openPoints; PathPoint lastPoint = openPoints[index];
Optimasi
Dengan hanya membagi jalur dari awal ke titik saat ini, kami mengurangi jumlah node berkali-kali dan membuatnya lebih serakah.
return this.heuristicEstimatePathLenght + this.pathLenghtFromStart /2;
Ringkasan
Pro:
- Pencarian cepat di ruang terbuka.
- Fleksibilitas algoritma
Cons:
- Membutuhkan banyak memori untuk menghitung rute.
Hijau menunjukkan daftar node terbuka, jalur merah ke target, node tertutup biru.
Rute yang diterima sebelum pengoptimalan: Menerima rute setelah optimisasi: Sastra
https://tproger.ru/articles/pathfindings/
https://ru.wikipedia.org/wiki/A*