2D kiremitli oyunda görüş alanını hızlıca nasıl hesaplayabilirim?


24

Bir karo matrisi var, bazı karoların üzerinde nesneler var. Hangi kiremitlerin oyuncu tarafından görülebildiğini ve hangilerinin görünmeyeceğini hesaplamak istiyorum ve oldukça verimli bir şekilde yapmam gerekiyor (bu yüzden büyük bir matris (100x100) ve bir sürü nesneye sahip olduğumda bile yeterince hızlı hesaplanacak).

Bresenham'ın çizgi algoritması ile yapmaya çalıştım , ama yavaştı. Ayrıca, bana bazı hatalar verdi:

----XXX-        ----X**-     ----XXX-
-@------        -@------     -@------
----XXX-        ----X**-     ----XXX-
(raw version)   (Besenham)   (correct, since tunnel walls are 
                              still visible at distance)

(@ is the player, X is obstacle, * is invisible, - is visible)

Bunun yapılabileceğinden eminim - sonuçta NetHack, Zangband var ve hepsi bir şekilde bu sorunla ilgilendi :)

Bunun için hangi algoritmayı önerebilirsiniz?


İhtiyaçlarım için, şöyle görülebilir olarak tanımlayacağım : kiremit en azından bir kısmı (örneğin köşesi) oyuncu kiremitinin merkezine herhangi bir engelle kesişmeyen düz bir çizgi ile bağlanabildiği zaman görünür.


1
Hata! Benim hatam, NetHack görüş hattını karıştırmıyordu :)
Rogach

Bazı eski fikirler fadden.com/tech/fast-los.html adresinde bulunabilir , ancak bu işlem CPU'ların oldukça yavaş olduğu ve kayan nokta hesaplamalarından kaçınılması gereken günlere dayanıyor.
fadden

Yanıtlar:


10

Visible tanımınız şudur:

Karoların en azından bir kısmı (örneğin köşesi), oyuncu karosunun merkezine herhangi bir engelle kesişmeyen düz bir çizgiyle bağlanabildiği zaman karo görünür

Bu konsepti kelimenin tam anlamıyla oynatıcı döşemenizden ışınları izleyerek ve sahnenize kesişerek uygulayabilirsiniz. Işın bir engele çarptığında (veya belirli bir mesafe eşiğini aştığında) her yinelemeden koparsınız, çünkü yalnızca oyuncunun doğrudan görebileceği çinilerle ilgilenirsiniz. İşlemi sizin için çözeceğim:

  1. Algoritmayı vermek istediğiniz hassasiyet seviyesini belirtin. Bu, takip edeceğiniz ışınların sayısı olacaktır.
  2. Her ışın arasında kaç derece dönüleceğini bilmek için tam 360 derece daireyi seçilen hassasiyete bölün.
  3. 0 dereceden başlayarak ve 2. adımda belirlenen miktarda artış yaparak, oyuncu karosunun ortasındaki orijinli ve mevcut açı ile belirlenen yöndeki bir ışın oluşturun.
  4. Her bir ışın için, oynatıcı döşemesinden başlayarak, bir engel döşemesini vuruncaya kadar ışının yönü boyunca yürüyün . Bu döşemeyi görünür döşeme listesine ekleyin ve bir sonraki ışına geçin. Çarpışma bulunmaması durumunda "pes" için maksimum bir mesafe eklemek isteyebilirsiniz.

İşte 3 örnek ışın gösteren bir resim. Koyu renkli döşemeler, her bir ışının “sonucudur”; Yine de bunu çemberin her tarafında tekrarlamanız gerekir:

görüntü tanımını buraya girin

Performans için maksimum mesafeyi ve ışın sayısını azaltın. Çok az ve fayans özledim, çok fazla ve performansınız acı çeker. Ayrıca, ışınların en uzağa seyahat etmesi gereken, "hata" ne kadar büyük olursa, ihtiyacınız olan hassasiyet de o kadar artar.

Düzenle

Algoritmanın kesişme bitini uygulamanıza yardımcı olmak için, özellikle Adım 3 ve Adım 4'teki yeniden yayınlama hakkında aşağıdaki öğreticiyi kontrol edin:

http://www.permadi.com/tutorial/raycast/rayc7.html


Sadece her ışın boyunca sabit bir mesafeyle (örneğin, 0,3 puan) "yürümek" mi yoksa Besenham'ın algoritması gibi bir şeyi her ışında mı çalıştırmam gerekir?
Rogach

Sadece sabit bir mesafeye ilerlerseniz, kaçırılan karolarla ilgili sorunlarınız olur. Bu bilgiyi yeniden yayınlama ile ilgili kontrol edin . Cevabımı da o resouce düzenleyeceğim. Temel olarak yatay ve dikey çarpışmaları ayrı ayrı kontrol edin.
David Gouveia

1
Algoritma iyidir, ancak uzun 1 karo genişliğindeki tünellerde doğru çalışması için büyük miktarda ışın gerekir.
HolyBlackCat

@HolyBlackCat - bu, yalnızca her yöne eşit açıda ışınları gönderirseniz geçerli olacaktır. Ancak bu ışınların çoğunu göndermekten kaçınabilir ve yalnızca sahnenizdeki satır sonlarına fırlatabilirsiniz. İşte iyi bir açıklama verilmiştir: redblobgames.com/articles/visibility
Rogach

8

Görüş ışınlarının yerine gölge ışınlarını kullanmayı tercih ederim.

Diyelim ki bu sizin görüş alanınız (potansiyel olarak görülebilir alan)

######################
#####.............####
###................###
##..................##
#....................#
#....................#
#..........@.........#
#....................#
#....................#
##..................##
###................###
#####.............####
######################

# Blokları, görünür durumdayken görünmez. görülebilir

Hadi biraz engel koyalım:

######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXXX...........#
##..................##
###....X...........###
#####.............####
######################

Görünüm alanı içinde bulunan X'in bir listesi var, sonra bu engelin arkasındaki her döşemeyi gizli olarak işaretlersiniz: bir engel gizlenmiş olarak işaretlendiğinde, listeden kaldırırsınız.

######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXX*...........#
##......##..........##
###....*#..........###
#####.###.........####
######################

Yukarıdaki örnekte, en alttaki duvarın sağ tarafından atılan gölgeyi ve bu gölgenin gizli engeli kontrol etmeniz gereken engeller listesinden nasıl sildiğini görebilirsiniz (X kontrol etmeli; * kontrol edilmeli).

Eğer listeyi bazı ikili partitonları kullanarak sıralarsanız, ilk Cosest X kontrol edilirse, kontrolünüzü biraz hızlandırabilirsiniz.

Bir kerede Xs bloğunu kontrol etmek için bir çeşit "Deniz Savaşları" algoritması kullanabilirsiniz (temelde gölge konisini daha geniş hale getirecek yönde olan bir adiacent X arıyorsunuz)

[DÜZENLE]

Düzgün bir gölge elde etmek için iki ışın gerekir ve bir çini dikdörtgen olduğundan, mevcut simetrileri kullanarak birçok varsayım yapılabilir.

Işın koordinatları, engel döşemesinin etrafına bölünen basit bir boşluk kullanılarak hesaplanabilir:

Uzay bölümleme örneği

Her dikdörtgen alan, kiremit köşesinin neyin gölge koni kenarı olarak alınması gerektiği konusunda bir seçimdir.

Bu akıl yürütme, birden fazla bitişik fayans bağlamak ve takip eden tek bir daha geniş koni dökmelerini sağlamak için daha fazla itilebilir.

İlk adım, gözlemci yönüne yönelik hiçbir engel bulunmadığından emin olmaktır, bu durumda en yakın engel bunun yerine kabul edilir:

en yakın engeli seç

Sarı kiremit bir engelse, o kiremit yeni kırmızı kiremit haline gelir.

Şimdi üst koni kenarını düşünelim:

aday fayans

Mavi kiremitlerin tümü, gölge konisinin daha geniş olmasına izin vermek için olası bir adaydır: en az bir tanesi engel ise, ışın daha önce görüldüğü gibi kiremit etrafındaki alan kullanılarak parlatılabilir.

Yeşil çini yalnızca gözlemci izleyen turuncu çizginin üzerindeyse adaydır:

genişletilmiş kontrol

Aynı şey, diğer ışın ve gözlemcinin kırmızı engel hakkındaki diğer konumları için de geçerlidir.

Temel fikir, her koni dökümü için mümkün olduğu kadar alanı kaplamak ve kontrol edilmesi gereken engeller listesini mümkün olduğu kadar kısaltmaktır.


İlginç yaklaşım ve muhtemelen çıkartıcı doğası nedeniyle daha iyi bir fikir. Bunu okuduktan sonra muhtemelen ben de bu şekilde uygularım.
David Gouveia

Ben gibi durumlarda, sorunların öngörebiliriz bu . Sarı oyuncu, mavi ve mor engeller. Oyuncunun gerektiğini (yeşil ışın gösterileri gibi) mor engeli görmek mümkün. Ancak mavi engelden geçen kırmızı gölge ışını mor taşı reddeder. Ancak görüş hattının versiyonunun bundan daha büyük sorunlara sahip olma potansiyeline sahip olduğunu düşünüyorum.
David Gouveia

Bu sorun "gizli" tanımından gelir: bir ışın bir kiremitle kesiştiği zaman (neredeyse) asla bunu tam olarak örtmez. Aynı bölüm, çizgi parçalarını oluştururken takma işlemlerle de çözülür. Şahsen ben bir karonun büyük bir kısmı kaplandığında gizli olduğunu, bir kişinin gizli olduğunu tanımlayabildiğini tamamen kapladığını düşünüyorum, potansiyel olarak gölge konisini daha geniş hale getirebilecek bir taraf ortaya çıkarsa bulabilirsiniz ... Her neyse, olabilir sadece tamamen kaplanmış blokları temizleyin.
FxIII

@DavidGouveia - daha büyük problemler?
Rogach

@DavidGouveia - Gölge "konileri" ile yaklaşımı çoktan denedim ve çok verimsizdi. Görünürlük ışınlarının hassasiyeti gelince - ~ 5500 ışınları, duvarın her bir yönüne doğrudan otururken her bir yönde 20 döşemeyi görmek için yeterlidir ve sadece tek bir döşemenin görülebildiği mesafe çok daha fazladır. Ve bazı karoları daha uzak mesafeden özlüyor olsanız da - herkesin görme yeteneği yoktur, öyle değil mi?
Rogach

8

Çözmeye çalıştığınız problem bazen kısaca FOV View alanı olarak adlandırılır. Roguelikes'den örnek olarak bahsettiğiniz gibi, RogueBasin wiki'nin konu hakkında neler söylediğine bir göz atmalısınız (uygulamalara bağlantılar bile var): http://www.roguebasin.com/index.php?title=Field_of_Vision

Farklı avantajları ve dezavantajları olan birkaç farklı algoritma vardır - RogueBasin'de de çok kullanışlı bir karşılaştırma yapılabilir: http://www.roguebasin.com/index.php?title=Comparative_study_of_field_of_view_algorithms_for_2D_grid_based_worlds


Gerçekten iyi ve eksiksiz bir özet!
Rogach,

Bu web sitesi harika bir kaynak, bu bağlantıyı paylaştığınız için teşekkürler. Ayrıca :-) nasıl A * pathfinding eserlerin şaşılacak anlaşılabilir açıklamasını içerir
uliwitness

Cevaptaki bağlantı şimdi sitenin ana sayfasına gidiyor - roguebasin.com/index.php?title=Category:FOV makul bir eşleşme olarak görünüyor.
Ocak'ta 16:16


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.