A * gezinme ağ yolu bulma


15

Bu yüzden, Greenfoot adlı çerçevede bu yukarıdan aşağı 2D java oyununu yapıyorum ve savaşacağınız çocuklar için AI üzerinde çalışıyorum. Onların dünya çapında gerçekçi bir şekilde hareket edebilmelerini istiyorum, bu yüzden kısa süre sonra fark ettim, birkaç şey arasında bir çeşit yol bulmaya ihtiyacım olacaktı.

İki A * prototipi yaptım. Biri ızgara tabanlı ve daha sonra ara noktalarla çalışan bir tane yaptım, bu yüzden şimdi engellerin / binaların 2d "haritasından" bir yol yapabileceğim bir düğüm grafiğine ulaşmanın bir yolunu bulmalıyım. Gerçek yol bulma iyi görünüyor, sadece açık ve kapalı listelerim daha verimli bir veri yapısı kullanabilir, ancak ihtiyaç duyduğumda ve gerektiğinde buna ulaşacağım.

Ben ai-blog.net bu yazıda sıralanan tüm nedenleri için bir gezinme kafes kullanmak niyetinde . Bununla birlikte, karşılaştığım sorun, A * 'nın düşündüğü şey, düğümün herhangi bir bölümünden geçtiğinizde çokgen merkezlerinden / kenarlarından en kısa yolun mutlaka en kısa yol olmamasıdır. Daha iyi bir fikir edinmek için stackoverflow ile ilgili sorduğum soruyu görebilirsiniz .

Görünürlük grafiğiyle ilgili iyi bir yanıt aldım. O zamandan beri kitabı satın aldım ( Hesaplamalı Geometri: Algoritmalar ve Uygulamalar ) ve konuyu daha fazla okudum, ancak yine de bir gezinme ağından yanayım ( Amit'in Yol Bulma ile İlgili Notlarından " Karmaşıklığı Yönetme " konusuna bakın ). (Bir yan not olarak, belki de ilk ve son gizlenmemişse birden fazla ara noktayı tek bir düz çizgiye dönüştürmek için Theta * 'yı kullanabilirim. Veya her hareket ettiğimde, sondan önce ara noktaya kontrol edin. buna)

Yani temelde istediğim, bir huni algoritmasıyla (örneğin, Digesting Duck'tan bu) koyduğum bir gezinme ağdır , sadece düğümü takip eden en kısa yol olan düğümü almak yerine, en kısa yolu alacağım, ancak bazı çokgenlerden geçip düğümleri / kenarları atlayabildiğiniz göz önüne alındığında gerçek olan en kısa değil.

Oh ve ben de çokgenlerle ilgili bilgileri nasıl saklamayı önerdiğini bilmek istiyorum. Yaptığım yol noktası prototip örneği için, her bir düğümü bir nesne olarak aldım ve o düğümden seyahat edebileceğiniz diğer tüm düğümlerin bir listesini sakladım, sanırım çokgenlerle çalışmayacak mı? ve bir poligonun açık / sürülebilir olup olmadığını veya katı bir nesne olup olmadığını nasıl anlarım? Çokgeni oluşturan hangi düğümleri nasıl saklarım?

Son olarak, kayıt için: Mevcut başka çözümler olmasına rağmen bunu kendim sıfırdan programlamak istiyorum ve bu oyunu başka bir şeyde (yeniden) kullanmak istemiyorum, bu yüzden önemli değil kaçınılmaz olarak kalitesiz olacaktır.


Emin değilim ama bu bağlantılar yardımcı olabilir: gamedev.stackexchange.com/questions/1327/… gamedev.stackexchange.com/questions/8087/… ayrıca şu anda bulamadığım başka bir soru daha vardı bir ödül aldı ve çok iyi bir cevabı vardı.
Ali1S232

Evet, ikinci bağlantıda birincil kaygımı görebiliyorsunuz, A * algoritması alt orta yolu en kısa kenar orta noktaları olarak veriyor, ancak engelin en üstündeki yol aslında en kısa. A * 'nın bana en üstteki yolu vermesini nasıl sağlayacağımı bilmek istiyorum (örneğin bir huni algoritmasıyla), gerçek en kısa yolu elde etmek için, o zaman bana en altta olanı verir gibi Düzleştirsem bile dolambaçlı yoldan gidiyor.
angrydust

Aslında, sadece gamedev.stackexchange.com/questions/8087/… ' daki makaleyi okudum ve A * ile bir rota bularak, daha sonra değiştirilmiş bir huni algoritmasıyla gerçek maliyetini hesaplayıp başka bir rota bularak ve hesaplayarak işe yarıyor gibi görünüyor. tekrar gerçek maliyet ve diğerinden daha kısa olup olmadığını görmek. En kısa rotayı bulduğunu bilene kadar tekrar eder. Bu gerçekten sorunumu çözüyor, ancak hem düzleştirme hem de yol bulma işlemini tekrarladığınız için oldukça yavaş olacak gibi görünüyor, ki bu oldukça maliyetli olacaktır.
angrydust

Çokgen depolama: yalnızca görünür çokgenleri saklayın - veya her bir çokgenle bir etiket ilişkilendirin (her çokgenin dairesel bir köşe listesi listesi olması gerektiğini unutmayın); düğümlere benzer şekilde, köken aldıkları çokgenin kimliğini saklayabilirsiniz - ancak size bunu söylememe gerek yok: bu temel veri depolama. Sonunda neden gerçek en kısa yolu önemsiyorsun ? Oyununuz köpeği yavaş çalıştırabilir veya biraz yanlış yollara sahip olabilirsiniz: birini seçin. En kısa gerçek yolu elde etmek Önce tam kapsamlı bir arama GEREKTİRİR (en azından bir düğüm grafiğinin üzerinde).
Jonathan Dickinson

Ben geçen piksele% 100 doğru olacaktır yolunu gerekmez biliyorum ve ben A'yı kullanabilirsiniz biliyorum @JonathanDickinson * en fazla olacak yolları üretmek için p kabuledilebilir. Yığın taşması veya gamedev.stackexchange.com/questions/8087/… ile ilgili önceki sorumda olduğu gibi, bir engel çok açık bir şekilde çok net gidiyor . Yapay zekamın bir engel etrafında yürümesine izin veremem!
kızgın toz

Yanıtlar:


14

Kendi kodunuzu yazacak olsanız bile, Recast'ı indirip oluşturduğunuz navmesh'i gösteren görselleştirmelere sahip örnek uygulamayı oluşturmanızı ve yol bulmayı basit bir nokta ve tıklama ile test etmenizi sağlar. arayüz. Sadece bununla oynayarak çok şey öğrenebilirsiniz.

Daha önce fark ettiğiniz gibi, iyi görünümlü bir yol üretmek için iki adım vardır - A * yol bulucu ve daha sonra yol düzleştirme (engellerden kaçınmak için gerekli olmayan herhangi bir dönüşün ortadan kaldırılması) ve daha sonra dönüş noktalarına eğrilerin eklenmesi.

Yol bulma

A * parçasına hakim oldunuz, bu harika. Ayrıca, A * 'nın her zaman en düz yolu bulamayacağını gözlemlediniz. Bunun, A * 'nın bir grafiğe en kısa yolu (düğümlerin boyutsuz olduğu matematiksel bir kavram olması) bulmak için bir ağa uyguladığınız için, bir şekilde öğeleri birbirine bağlamak için düğümleri eşlemeniz gerektiğinden anlamak önemlidir.

Yapılacak en açık şey, çokgen merkez noktasından merkez noktasına gitmek ve maliyeti bu mesafeye dayandırmaktır, ancak bunun bazı sorunları vardır. Birincisi, geometrik olarak en kısa yolu bulamayacak ve ikincisi, hesapladığınız yolu denerseniz ve takip ederseniz, bir merkezden diğerine düz bir çizginin, çokgen olmayan bir çokgeni geçebileceğini fark edeceksiniz. yolun bir parçası değil (ve hiç gezinebilir). A * yaparken grafik geçişine mal olmak için korkunç bir yol değildir, ancak herhangi bir çapraz amaç için açıkça yeterli değildir.

Bir sonraki en basit çözüm, ağ boyunca kenardan kenara A * yapmaktır. Çokgen başına bir düğüm yerine, çokgen başına kenar başına bir düğümünüz olduğunu hayal ediyorsanız bunu düşünmek daha kolay olacaktır. Böylece yolunuz başlangıç ​​noktanızdan en yakın kenarın içine doğru gider, bitişik çokgenin kenarının hemen içine ve ardından aynı çokgenin bir sonraki kenarının içine geçer. Bu, en kısa yolu daha sık üretir ve ayrıca bir yol düzleştirme adımı gerçekleştirmek istemiyorsanız geçilebilir olma avantajına sahiptir.

Yol düzeltme

Detour'da (Recast'a eşlik eden navigasyon kütüphanesi) kullanılan algoritma oldukça basittir. Sadece A * araması sırasında bulunan çokgenlerin sınırları içindeki yolu düzelteceğini gözlemlemelisiniz. Bu nedenle, eğer bir engelin etrafındaki en dar yolu bulamazsa, o algoritmayı çalıştırdıktan sonra da sıkı bir yol elde edemezsiniz. Uygulamada, yeniden şekillendirme ile üretilen navmeshes, bir boğulma noktasında (iki engel arasındaki en yakın nokta) geçerken geçirebileceğiniz tek bir çokgene sahip olma eğilimindedir ve bu nedenle A * her zaman engele en yakın olan düğümlerin bir listesini üretir mümkün. Fayansları navmesh olarak kullanıyorsanız, durum böyle olmayacak ve bu çok basit algoritma sahte dönüşler ekleyecektir.

Detour'un yol doğrultma algoritması karmaşıklıkta oldukça O (n) değildir, çünkü bir dönüş eklemesi gerektiğini belirlediğinde, huniyi en son sola sıktığı noktaya yerleştirir (sola veya tam tersine) ve daha sonra bu noktadan tekrar düğümleri izlemeye başlar.

A * yolunun bir parçasını oluşturan çokgenlerin dışındaki yolu düzeltmek istiyorsanız, işler çok daha karmaşık hale gelir. Navmesh'inizdeki iki noktanın birbirini görüp göremeyeceğini test edebilen bir ışın döküm rutini uygulamanız gerekecek (A * kullanmanız gerekip gerekmediğini görmek için yine de buna sahip olmalısınız). Bunu, başlangıç ​​noktasında oluşturulan çizgi parçasını başlangıç ​​noktasını içeren çokgenin bağlantı kenarlarıyla kesişerek ve ardından sizi hareket ettiren çokgenin bağlantı kenarlarını test ederek yaparsınız. Bağlanmayan bir kenarla kesişirseniz (onlara kenarlık kenarları diyorum), o zaman bir engele çarpmış olursunuz.

Daha sonra, huni algoritması gerçekten işe yarayıp yaramadığını görmek için bir dönüş eklemesi gerektiğini belirlediğinde bu ışın dökümü testini gerçekleştirebilirsiniz, ancak bir dönüş ekleyene kadar bu testi her düğümde yapmaya devam etmeniz gerektiğini düşünüyorum ( hangi noktaya basit huni algoritmasına dönebilirsiniz). Bu pahalı hale gelecek ve yolun yaklaşık O (n ^ 2) düzleştirmesini sağlayacaktır.

Navmesh'i temsil etmek

Kafesinizi bir çokgen sınıfı dizisi olarak temsil edebilirsiniz. Çokgen sınıfı, bir köşeler dizisi ve varsa her kenar için bitişik çokgene referans dizisi kadar basit olabilir. Tabii ki bunu daha kompakt bir şekilde saklamanın yollarını düşünebilirsiniz. Bir tepe noktası genellikle birkaç çokgen tarafından paylaşıldığından, büyük bir köşe dizisine sahip olmak ve daha sonra her bir çokgen deposu dizinini bu diziye almak normaldir. Navmesh'inizin özelliklerine bağlı olarak, kenar sayısının sadece% 50'si veya daha az olan ortalama bağlantı kenarı sayısına sahip olabilirsiniz. Bu durumda, her kenar için bir bağlantı saklamak yerine başka bir çokgene bağlantı ve kenar dizinini saklamak isteyebilirsiniz. Ayrıca, bir sınıf referansı kullanmak yerine çokgenin dizinini navmesh'in çokgen dizisinde saklamanızı öneririm.


Bunu kısa bir şekilde okudum, ama anladım ki A * için mesafenin karesini kullanmamalısınız (ya da karekök değil): theory.stanford.edu/~amitp/GameProgramming/…
angrydust

Gerçekten yol düzleştirme atm hakkında nasıl gitmek endişe değilim, ne hakkında endişe ediyorum ne diyorsun: "Sadece A * arama sırasında bulunan çokgen sınırları içinde yol düzeltmek gözlemlemelisiniz Bu şekilde, eğer bir engelin etrafındaki en dar yolu bulamazsa, o algoritmayı çalıştırdıktan sonra da dar bir yol elde edemezsiniz. "
angrydust

Köşeler / orta noktalar üzerinden seyahat etmenin maliyeti ne olursa olsun, A * 'nin her zaman düzeltilen yolu en kısa olan yolu bulacağı bir gezinme ağına sahip olmak istiyorum. Bunun görünürlük grafiğiyle yapılabileceğini takdir ediyorum, ancak başka bir faydası olduğu ve bir görünürlük grafiğinin karmaşıklığı çok hızlı büyüyebileceğinden bir navmesh kullanmak istiyorum: theory.stanford.edu/~amitp/GameProgramming/…
angrydust

@theguywholikeslinux Öklid mesafesini kullanabilirsiniz sqrt(x*x + y*y)- ancak düğüm başına daha ucuz değil x*x + y*y.
Jonathan Dickinson

@JonathanDickinson Biliyorum, dolayısıyla benim açımdan.
11:29
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.