Perlin gürültüsüyle yapılan bir dünyada yumurtlama birimleri?


16

Perlin gürültüye dayalı oyunumda karşılaştığım bazı sorunlar var. Aşağıdaki ekteki ekran görüntüsüne bir göz atın.

resim açıklamasını buraya girin

Gördüğünüz beyaz alanlar duvarlar ve siyah alanlar yürünebilir. Ortadaki üçgen oyuncu.

Bu oyunda fiziği bir dokuya (beyaz veya siyah piksel) çizerek ve ardından CPU'dan alarak uyguladım.

Ancak şimdi elimde farklı bir sorun var. Ekranın kenarında birimlerin (ya da onları ne derseniz deyin) sürekli ortaya çıkmasını istiyorum. Buradaki nokta, son oyunda, oyuncunun bunu çok fazla görmesine izin vermeyen bir "savaş sisi" olacağı.

Ekranın kenarındaki pikselleri tarayabildiğimi ve fizik dokularının siyah olup olmadığını anlayabildiğimi ve sonra rastgele rastgele bir şeyler üretebileceğimi düşündüm. Ancak, ekran görüntüsüne ikinci kez bakarsanız, (sol üst köşede) sürüngenlerin ortaya çıkmasını istemeyeceğim bir örnek var (çünkü oradan oyuncuya ulaşamayacaklar) .

GPU'nun bu yumurtlama noktalarını bir şekilde benim için veya başka bir şekilde belirlemesini sağlamak mümkün mü? Ekranın kenarındaki önerilen nokta ile oyuncu arasında vektörler yapmayı ve sonra her 10 vokselde bir izlemeyi düşündüm ve orada bir birim yumurtlamadan önce bir duvarın çarpışıp çarpışmadığını görün.

Bununla birlikte, yukarıda önerilen çözüm çok CPU yoğun olabilir.

Bu konuda herhangi bir öneriniz var mı?

Not 1 Ortaya çıkan birimler için, duvardaki çarpışmalardan kaçınmak için herhangi bir yol bulma yöntemi kullanmak istemiyorum, çünkü bu birimler oynatıcıya doğru ilerliyor. Olur oyuncuya doğru düz bir çizgide yürüyen nereye nedenle, birimler bir yerde, ekranın kenarında yumurtlamaya gerekir değil herhangi duvarlarla çarpışır.


1
Harita oynatıcıyla birlikte mi hareket ediyor yoksa harita üzerinde hareket ediyor mu? Yani harita değişecek mi? Değilse, nesildeki ulaşılamayan tüm noktaları doldurmanızı öneririm, böylece onlar için endişelenmenize gerek kalmaz.
dlras2

Oynatıcı hareket ediyorsa, birimlerin bir yol bulma yöntemine ihtiyacı olacaktır. İçbükey alanlar istiyorsanız bu sorunla karşı karşıya kalacaksınız ve hareketli bir oyuncuya ulaşmaya çalışan hareketli ünite için bir çözüm sağlamanız gerekiyor ... aka yol bulma.
Blau

1
Veya Blau'nun yorumunu başka bir şekilde ifade etmek için: Oyuncu hareket edebiliyorsa, sorunuzun geçerli bir cevabı yoktur (oyuncunun duvar karosu / pikseli olmayan bir haritanın önemsiz durumu dışında). Yine de, oyuncu sabit durumdaysa bir cevap almak için "düz çizgi" ile ne demek istediğinizi tanımlamanız gerekir.
Martin Sojka

Yanıtlar:


3

Bu iş için oldukça kullanışlı bir algoritma var, bu durumda taşkın algoritmasından çok daha verimli (karmaşıklığı, çalışma zamanının taşkın alanından ziyade sınır boyutuyla orantılı olması): yürüyen kareler algoritması. Konsept basit: oyuncuların konumunu (ekran orta noktası) başlatın, bir yön seçin ve bir duvar bulana kadar yürüyün. Duvarla çarpıştığınızda, algoritmayı başlatırsınız: bir yönlendirme (yukarı veya aşağı) seçersiniz ve pikselleri vurgulayarak bu alanın sınırı boyunca yürümeye başlarsınız. Bu size izin verilen alanın iç sınırını verir. Daha sonra, yumurtlama birimleri için aday noktaların bu sınırda olup olmadığını kontrol edersiniz.

Sınırı çalıştırmak için izlemeniz gereken prensip budur:

http://en.wikipedia.org/wiki/File:Marchsquares.png (meh Henüz fotoğraf gönderemiyorum)

Wikipedia açıklaması (daha fazla karmaşıklığa sahip olmasına rağmen, diğer uygulamalar düşünülerek kullanıldığından):

http://en.wikipedia.org/wiki/Marching_squares


10

Oyuncunun konumundan bir taşkın dolgu yapın ; o zaman "sular altında" her alan geçerli bir oyun alanı ve diğerleri duvarlar.

EDIT: "düz bir çizgi ulaşılabilir" ek gereksinimi gelince, ayrı bir alanda , bunu biraz daha tanımlamak gerektiğini unutmayın. Örneğin, yukarıdaki tüm yollar böyle bir ortamda geçerli bir "düz çizgi" olabilir ve hepsinin bir noktada bir oyunda kullanıldığını gördüm:

"straight line" variants

Özellikle, bunların çoğu değişmeli değildir - bu da A'ya B'den "düz bir çizgide" ulaşabileceğiniz anlamına gelmez, A'ya B'den de ulaşabileceğiniz anlamına gelmez; aksi tam tersi de doğru değildir.

Ayrıca, "yan" noktalardan biri veya her ikisi de engelleniyorsa çapraz hareketi nasıl ele alacağınız sorusu vardır.


Bu tamamen HLSL'de uygulanabilir mi?
Mathias Lykkegaard Lorenzen

@Mathias Lykkegaard Lorenzen: Evet, şüphesiz algoritmanın her adımını piksel gölgelendirici olarak yaparak ve örneğin iki doku hedefi arasında görüntü oluşturarak, ama ... neden ? En azından yol bulmak için muhtemelen CPU'daki algoritmadan gelen bilgilere ihtiyacınız olacaktır.
Martin Sojka

1
@Mathias Lykkegaard Lorenzen: Bu, istediğinden biraz farklı. Bu durumda: Ayrık alan bölümleme şemanız göz önüne alındığında bir "düz çizgi" nasıl tanımlanır?
Martin Sojka

2
pathfinding kullanmak istemeseniz bile, cpu'dan floodfill işini yapmasını istemek mümkündür, ancak floodfill'i bir kez çağırmanız gerektiğini unutmayın ve daha sonra duvar, boş alanlar ve yumurtlanabilir alanları tanımlayan 3 renk bir dokuya sahip olacaksınız. 4096x4096 doku için cpu'nun taşkın doldurma işini tamamlaması bir saniyeden az sürer.
Ali1S232

1
Mesele şu ki, bu taşkın dolgusunu sadece bir kez çalıştırmak zorundasınız ve oyun sırasında araziniz değişse bile, sadece etkilenen bölümleri güncellemeniz ve bunlardan çok hızlı olan taşkın dolgularını çalıştırmanız gerekiyor.
TravisG

1

Yumurtlamaların gerçekleşmesine izin vermeye ne dersiniz? Bunda özel bir sorun görmüyorum.


Ya bir duvarın arkasında ortaya çıkarlarsa? Oyuncuya ulaşmalarını nasıl sağlıyorsunuz?
Mathias Lykkegaard Lorenzen

1
Oyunda tüm düşmanları öldürmek için bir senaryo varsa sorun olabilir ve 50 düşman doğurur, ancak birkaç tanesi duvarın arkasında ortaya çıkar. Oyuncu düşmanları öldüremez ve senaryo bitmez.
Yalan Ryan

1
Diğer birimler, oyuncunun doğduktan sonra nasıl hareket ettiğine bağlı olarak oyuncuya ulaşamayabilir, her iki durumda da bazı birimlerin eşleştirmesini kaldırmanız gerekir.
aaaaaaaaaaaa

savaş sisi berbat spawns kapsayacak
KRB

1
Oyuncu hareket ettiğinde bu zaten çalışmaz.
aaaaaaaaaaaa

1

oyuncuya sadece geçerli bir düz çizgiyle noktaları işaretlemeniz önemliyse, aşağıdakine benzer bir algoritma kullanabilirsiniz (bu bir c ++ kodu), normal taşkın dolgudan daha fazlasını tüketir. kod kendim test etmedi çünkü bazı küçük hatalar (kimse onları düzeltirse sevinirim) olabilir ama fikir alırsınız.

void straightlineFill(Point startPoint, Texture target)
{
    queue<Point> pointQueue;
    for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(startPoint.x + dx, startPoint.y + dy));
    while (!pointQueue.empty())
    {
        point front = pointQueue.front();
        pointQueue.pop();
        if (target.pixelAt(front) == COLOR_SPAWNABLE||
            target.pixelAt(front) == COLOR_WALL||
            target.pixelAt(front) == COLOR_NOT_SPAWNABLE)
                continue;
        taraget.setPixelAt(front, colorFilled); 
        for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(front.x + dx, front.y + dy));
        // up until now was the normal floodfill code
        // and here is the part that will do the real straight line checking

        // lineDX & lineDY will keep how much the line we are checking is skewed
        int lineDX = front.x - startPoint.x;
        int lineDY = front.y - startPoint.y;

        // step will show us how much we have to travel to reach each point of line
        point step;
        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDX < 0)
                step = point(-1,0);
            if (lineDX == 0)
                if (lineDY < 0)
                    step = point(0,-1);
                else
                    step = point(0,1);
            if (lineDX > 0)
                step = point(1,0);
        }

        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDY < 0)
                step = point(0,-1);
            if (lineDY == 0)
                if (lineDX < 0)
                    step = point(-1,0);
                else
                    step = point(1,0);
            if (lineDY > 0)
                step = point(0,1);
        }

        // moved will keep how much we have traveled so far, it's just some value that will speed up calculations and doesn't have any mathematical value
        point moved = 0;

        // spawnable will keep if the current pixel is a valid spawnpaint

        bool spawnable = true;

        // now we will travel on the straight line from player position to the edges of the map and check if whole line is valid spawn points or not.

        while (target.isInside(front))
        {
            front = front + step;
            moved = moved + point(step.x * lineDX, step.y * lineDY);
            if (step.x != 0 && moved.x < moved.y)
            {
                moved.x = moved.x - lineDY * sign(lineDY);
                front.y = front.y + sign(lineDY);
            }
            if (step.y != 0 && moved.y < moved.x)
            {
                moved.y = moved.y - lineDX * sign(lineDX);
                front.x = front.x + sign(lineDX);
            }

            if (target.getPixelAt(front) == COLOR_WALL)
                spawnable = false;

            if (spawnable)
            {
                target.setPixelAt(front,COLOR_SPAWNABLE);
                for (int dx = -1;dx <=1;dx ++)
                    for(int dy = -1;dy <=1;dy++)
                        if(dx != 0 && dy != 0)
                            pointQueue.push(point(front.x + dx, front.y + dy));             
            }
            else
            {
                target.setPixelAt(front,COLOR_NOT_SPAWNABLE);
            }
        }
    }
}

1

Haritayı dışbükey alanları temsil eden renklerle doldurabilirsiniz ..., böylece aynı bölgede yer alıyorsa ünitenizi oluşturabilirsiniz. Veya ulaşılabilir alanları daha kolay arayabilirsiniz.

Bu statik veridir, böylece önceden hesaplayabilirsiniz.

içbükeyden dışbükeyde bir değişiklik olan görüntü bulma noktalarını doldurmanız gerekiyordu, görsel olarak bulmak kolay görünüyor, iki durumunuz var:

  1. Yatay: Turuncudan maviye değiştiği yer.
  2. Dikey: Kırmızının yeşil ve turuncu renkte değiştiği yerler.

resim açıklamasını buraya girin


Bu işe yaramıyor. Sağ alt kısma, özellikle kırmızı bölgedeki lekeye bakın. Tamamen dışbükeydir, bu nedenle başka bir rengin kullanılmasına neden olacak bir değişiklik yoktur, ancak sağ kenardaki kırmızının altından alt kenardaki kırmızının en sağına kadar düz bir çizgi yoktur.
Loren Pechtel

@Loren Pechtel bu el yapımı, haklısın, orada bir hata var, bu benim hatam, ama bunun turuncudan maviye geçişle aynı durum olduğunu fark edebilirsiniz.
Blau

@Loren Pechtel, objektifin sarı gibi alanlarda yumurtlamaktan kaçındığını hatırlatın. Bu yöntem, oyuncuyu içeren aynı alanda bir düşmanı serbest bırakırsanız buna ulaşılabilir olmasını sağlar. Tabii ki, uygulanması zor olabilir, ancak fikir geçerlidir.
Blau

Düzeltmeniz yardımcı olmuyor. Dışbükey bir eğri üzerindeki iki noktanın, aralarında hiçbir zaman yasal düz bir çizgi olmayacaktır. Daha fazla bölünme yardımcı olmaz.
Loren Pechtel

lütfen dışbükey tanımını alanlara veya nokta kümesine atıfta bulunarak kontrol edin ... en.wikipedia.org/wiki/Convex
Blau

1

İşte kendi oyunumda kullandığım bir şey (neredeyse sizinki gibi 2d simpleks gürültü üretilen dünya) - Rays. Oynatıcıdan başlayın, bir yönlendirme belirleyin (isterseniz rastgele) ve bir şeye çarpana kadar (ekranın kenarı VEYA asteroit) o ​​çizgi boyunca ilerleyin. Ekranın kenarına vurursanız (asteroit / beyaz bir damla değil), ekranın kenarından oynatıcıya düz, açık bir çizgi olduğunu bilirsiniz. Sonra vurduğunuz noktada bir canavar yaratın. Bir asteroit vurursanız testi tekrar yapın.


0

Kullanabileceğiniz başka bir (GPU olmayan) çözüm, yol bulmadır. Haritayı çizmeden önce, haritanın her bir kenarındaki olası her bir çıkış noktasından yol bulun ve merkeze bir yol olup olmadığını görün. Bir * yol bulma maliyet / performans açısından oldukça uygundur, ancak bu bir sorun varsa oyun başlamadan önce yapabilirsiniz.

Yolu olmayan herhangi bir yumurtlama noktası bir hariç tutma listesine konulabilir; veya tam tersi (bir yol içeren herhangi bir nokta bir dahil etme listesine konabilir).

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.