Birbirini görebilen birimleri gruplandırmanın en hızlı yolu?


12

Birlikte çalıştığım 2B oyunda, oyun motoru bana her birim için kendi görüş aralığındaki diğer birimlerin listesini verebilir.

Her bir grubun birbirine ("diğerleri" aracılığıyla) bağlı olan tüm birimler tarafından tanımlanacağı birimleri gruplar halinde sıralamak için yerleşik bir algoritma olup olmadığını bilmek istiyorum .

Bir örnek, sorunun daha iyi anlaşılmasına yardımcı olabilir (E = düşman, O = kendi birimi). Önce oyun motorundan alacağım veriler:

E1 can see E2, E3, O5
E2 can see E1
E3 can see E1
E4 can see O5
E5 can see O2
E6 can see E7, O9, O1
E7 can see E6
O1 can see E6
O2 can see O5, E5
O5 can see E1, E4, O2
O9 can see E6

Sonra grupları aşağıdaki gibi hesaplamalıyım:

G1 = E1, E2, E3, E4, E5, O2, O5
G2 = O1, O9, E6, E7

Görüş alanı için değişmeli bir özellik olduğu varsayılabilir: [A B'yi görürse, B A'yı görür].

Sadece açıklığa kavuşturmak için: Zaten oyun motoru bilgilerinin her satırında döngüler yaratan naif bir uygulama yazdım, ama görünüşe göre, derinlemesine çalışılmış ve çeşitli yerleşik algoritmalara sahip olabilir (belki de geçiyor) ağaç benzeri bir yapı ile?). Benim sorunum yararlı google hit döndürdü sorunumu açıklamak için bir yol bulamadı olmasıdır.

Yardımınız için şimdiden teşekkür ederim!


1
Bence bu soru yığın akışında ve hatta matematikte (set teorisi?) Daha iyi cevaplar alabilecek kadar geneldir. Benim için oyun geliştirme özel değil.
Tor Valamo

1
@Tor - Muhtemelen doğrudur, ancak bunun bir oyun için olduğunu bildiğimiz gerçeği, insanların soruna daha spesifik cevaplar üretmelerine izin verebilir.
Robert Fraser

Sanırım mekansal karmaşa ve görünürlük haritasındaki bir spin ile akıllıca şeyler yapabilirsin - sadece düşünmem gerek.
Jonathan Dickinson

Yanıtlar:


7

"Görebilir" ilişkiniz simetrik ise, "A B görebilir" ifadesi "B görebilir A" anlamına gelir, o zaman hesaplamak istediğiniz gruplar "görebiliyor" ilişkisi tarafından tanımlanan grafiğin bağlı bileşenleridir . Diğerlerinin belirttiği gibi, bunları hesaplamak için basit algoritmalar vardır, örneğin:

while ungrouped units remain:
    let u = arbitrary ungrouped unit
    let g = new group
    let s = temporary stack
    assign u to g
    push u onto s
    while s is not empty:
        let v = topmost unit in s
        remove v from s
        for each unit w that v can see:
            if w is ungrouped:
                assign w to g
                push w onto s
            end if
        end for
    end while
 end while

("Yeni öğe ekle" ve "bazı öğeleri kaldır ve geri gönder" işlemlerini etkin bir şekilde uygulayan bir kuyruk veya başka bir koleksiyon syukarıdaki yığın yerine kullanılabilir .)

"Görebilir" ilişkiniz simetrik değilse , gruplarınızın güçlü veya zayıf bağlı bileşenler olmasını isteyip istemediğinize karar vermeniz gerekir . Zayıf bağlanmış bileşenler için, yukarıdaki algoritma olduğu gibi çalışacaktır, ancak hattın for each unit w that v can seedeğiştirilmesi gerekir for each unit w that can see v, or that v can see. İçin kuvvetle bağlı bileşenler , sen algoritmaları birini (kullanabilirsiniz Kosaraju en , Tarjan en ya Gabow en bağlantılı Vikipedi sayfasında belirtilen).

Simetrik olmayan ilişkiler için, ilişkinin veya güçlü bir şekilde bağlı bileşenlerinin geçişli kapanışını da hesaplamak isteyebilirsiniz . Bunun için Floyd – Warshall algoritmasını kullanabilirsiniz ; daha fazla bilgi için SO'daki bu cevaba bakınız .


Ps. Yukarıdaki notlara bağladığım Wikipedia makalesi olarak, görünürlük ilişkisi değiştikçe grupları dinamik olarak güncellemek daha verimli olabilir. Wikipedia'da bahsedilen gelişmiş (?) Algoritmalara aşina değilim, ancak en azından her seferinde grupların sıfırdan yeniden hesaplanmasını yenen bir şeyi bir araya toplamak zor olmamalı.

Bunun yarısı kolay: eğer farklı gruplardaki iki ünite aralarında bir görüş hattı elde ederse, grupları birleştirin. Birbirlerini gözden kaybeden birimlerle uğraşmak biraz daha zor; basit ama belki de en uygun olmayan çözümlerden biri, etkilenen gruptaki birimler için gruplama algoritmasını her çalıştığında yeniden çalıştırmaktır. Görünürlük değişiklikleri bir seferde bir çift ünite meydana gelirse, bunu yapabileceğiniz bazı optimizasyonlar vardır:

  • Bir birim yalnızca başka bir birimi görebiliyor ve görüşünü kaybediyorsa, bir önceki grubundan çıkarın ve yeni bir gruba atayın.
  • Aksi takdirde, etkilenen birimlerden birinde başlayabilir ve diğer birim için görünürlük grafiğinde (ör. Sezgisel olarak düz çizgi mesafesi kullanarak) A * araması yapabilirsiniz . Eğer bulursan, grup ayrılmadı; bunu yapmazsanız, aramanın ziyaret ettiği birim kümesi yeni grubu oluşturur.
  • İki üniteden hangisinin bölünmüşse grubun daha küçük yarısına ait olduğunu tahmin etmeye çalışabilir ve aramayı bu üniteden başlatabilirsiniz. Bir olasılık her zaman doğrudan daha az sayıda başka birimi görebilen birimden başlamak olabilir.

4

Elinizde bir bağlantı grafiği var. Ve genellikle, bağlı düğümleri (yani: karakterleri) birlikte gruplamanın en iyi yolu bir grafik arama algoritmasıdır. Önce derinlik, önce genişlik, hangisi olursa. Yaptığınız tek şey, diğer düğümlerden hangi düğümlere erişilebileceğini gösteren bir liste oluşturmaktır. Grafiğiniz yönlendirilmediği sürece (A B için görünürse, B A için görünürse), bu iyi çalışır.

Belirli durumlar için bunu iyileştirmek için bazı algoritmalar olabilir. Örneğin, bazen karakterler hareket etmezse (ve arazi de hareket etmezse, hareketsiz karakterler görünür kalır), bağlantı grafiklerini güncellemek için bunları tekrar test etmemeyi seçebilirsiniz.

Ancak genel olarak, her karede görünürlüğü yeniden test etmeniz gerekir. Oranlar, görünürlük gruplarını bulmak için grafik geçişinden daha yavaş olacaktır.


3
Sadece teknik terimi eklemek için: bulmaya çalıştığınız şey grafiğin bağlı bileşenleri ve standart algoritma: (1) tüm düğümleri bir listeye koyun, (2) bir düğüm seçin, (3) bulmak BFS / DFS kullanan tüm bağlı düğümler, (4) listeden bulduğunuz tüm düğümleri kaldırır, (5) artık düğüm kalmayıncaya kadar tekrar eder.
Nathan Reed

3

Standart bir grafik bağlantı sorunu gibi görünüyor. Bunun için bir çeşit algoritma olabilir ve aşağıdaki gibi görünebilir:

remaining units = all units
for each unit in remaining units:
    current group = create a new group
    add this unit to current group
    for each unit visible to this unit:
        if unit is in a group already:
            merge current group into that existing group
            set current group as that existing group
        else:
            remove that unit from remaining units
            add that unit to current group

Bunu hiyerarşik kümeleme gibi bir ağaç üzerinden uygulamak mümkündür, ancak daha hızlı çalışacağından şüpheliyim - ağaçlar O (log N) olma eğilimindeyken, yukarıda verdiğim kontrollerin çoğu O (1) olarak uygulanabilir .


İlgi alanı dışında, hiyerarşik kümeleme yaklaşımı biraz şöyledir: Her birim için bir grup oluşturun. Ardından, birbirini görebilen her birim çifti için, eğer farklı gruplardalarsa, grupları bir araya getirin ve diğerini atın.
Kylotan

OP'imde saf uygulama olarak adlandırdığım şey bu . O zaman düşündüğüm kadar kötü olmayacağını bilmek güzel! :)
mac

Bunu ağaç olarak yapmanın yolu, yol sıkıştırmalı bir birleşim kümesi kullanmaktır . Bu çok naif değil ve aslında en uygunudur.
Peter Taylor

2

Bu bir grafik bağlantı sorunu olarak yanıt veren tüm diğerleriyle aynı fikirdeyim, ancak burada ihtiyacınız olan şeyin ilgili tüm birimlerinizden oluşturulan Delaunay Nirengi grafiği olduğunu belirtmeme izin verin . Bunun yaptığı, oluşturduğunuz grafiğe yalnızca birbirine en yakın birimlerin bağlanmasını sağlar. Bunu başka herhangi bir şekilde yapmayı çok zor bulacaksınız, çünkü grafik geçişleri (düzlemsel olmayan) birbirinden çok uzak birimlerin grafik içinde yanlış bağlanmasına neden olacaktır.

Yukarıdakiler yalnızca sürekli bir boşluk (çoğu serbest hareketli FPS'de olduğu gibi) kullanıyorsanız geçerlidir; ancak, birimlerinizin üzerinde hareket ettiği bir altta yatan ızgara (düzlemsel bir grafik) varsa, bunun yerine bağlantıyı değerlendirmek için bunu kullanabilirsiniz.

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.