Dörtlü ağaçlar / ızgara tabanlı çarpışma - mantığı harekete geçirme


13

Her şeyden önce, sadece kısa bir süre için kendi oyun mantığımı yazıyorum, bu yüzden bu doğru görünüyorsa özür dilerim.

Dörtlü ağaçlar ve ızgara tabanlı çarpışma tespiti hakkında çok şey okudum. Mantık anlıyorum - temelde nesneler yakın olmadığı sürece temelde çarpışma kontrolü yapmayın. Ancak bunun gerçekte nasıl yürütüldüğünden asla bahsedilmez.

Kafamda birkaç olası yöntem var ama hangisinin en iyisi olduğundan emin değilim

Genel çarpışma testi - optimizasyon yok

for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.collidesWith(objectB){

               //handle collision logic
              }
        }

komşuları depola (yöntem 1) Ancak, çarpışmaları yalnızca yakınlardaki nesneleri denetlemek üzere en iyi duruma getirmek istiyorsak. Hala tüm nesneler üzerinde mi çalışıyoruz, yoksa kontrol edilecek yakın nesnelerle bir dizi oluşturuyor muyuz?

var objects:Array = new Array();
    var neighbours:Array = new Array();

    for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.isNear(objectB){

               neighbours.push(objectA, objectB);
              }
        }

    }

    //somewhere else
    for(i:int = 0; i < neighbours.length; i++){
        //only check neighbours

        for(j:int = i + 1; j < neighbours.length; j++){

            if(objectA.collidesWith(objectB){

               //handle collision logic
              }
        }
    }

tüm nesneleri döngüye sokun, ancak sadece komşuları çarpışma açısından kontrol edin (yöntem 3) Diğer olasılık, yine de her şeyi döngüden geçirmemiz, ancak çarpışmayı test etmeden önce nesnelerin yakın olup olmadığını kontrol etmemizdir.

for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.isNear(objectB){
               //they are near - check collision!
               if(objectA.collidesWith(objectB){

               //handle collision logic
              }
            }
        }

    }

Nesneleri döşeme verilerinde saklama (yöntem 3) Döşeme tabanlı bir sistem kullanmak başka bir seçeneğe izin verir; Döşeme verilerindeki belirli bir döşemede bulunan nesneleri saklayın. Nesnenin etrafındaki döşemenin hangi döşemede olduğunu, çarpışabileceği nesneleri içerdiğini kontrol edin:

var ObjectA;

for(var i:int = 0; i < 4; i ++){
//check 4 surrounding tiles from object A

   if(Object.currentTile + surroundingTile[i] CONTAINS collidable object){
   //check collision!
    if(objectA.collidesWith(surroundingTile.object){

    //handle collision logic
     }

}
}

Her zaman gerçek dünyaya örnek olarak bakmaya çalışıyorum. Öğeleri aynı renkle karşılaştırmak istersem, renkle eşleşmese bile tüm öğelerin tümünü kontrol etmek mantıksız görünecektir (Yöntem 2, her öğeyi kontrol edin). Muhtemelen her şeyi kontrol etmek yerine aynı renkteki öğeleri (birbirine yakın nesneler) toplar ve bunları (yöntem 1) kontrol ederim.

Çarpışma kontrolündeki öğeler sürekli hareket ettiği için sipariş karışık hale geldiği için bu uygun bir karşılaştırma değildir. Beni şaşırtan şey bu.

Her öğeyi kontrol etmek daha verimli olur mu, böylece bir dizi komşu üretmeye devam etme zorluğunu ortadan kaldırır mıydı.

Yoksa çarpışmayı kontrol etmek için çok fazla nesne arasında dolaşmak zorunda kalmadan komşuları bulmak daha mı verimli?

Her kiremit veri değiştirmek de çok yoğun görünüyor, bu yüzden bu iyi bir fikir olup olmadığından emin değilim ..

Kulenin nesneleri vurmadan önce menzil içinde olup olmadığını tespit etmesi gereken bir kule savunma oyunu düşünüyordum. Ve tüm öğeleri kontrol etmek aptalca görünürken, bazı zamanlarda yakınlarda herhangi bir nesne olmayacaktır.

Uzun yazı için özür diliyorum, her zaman kendimi açıklamakta zorlanıyorum!


Bu hangi dil? JavaScript?
Kyle C

2
Actionscript 3, ancak dil oldukça ilgisiz. Sadece bunu idare etmek ve yapılandırmak için en iyi yolun ne olduğunu öğrenmek istiyorum :)
omgnoseat

Yanıtlar:


8

Gerçek çarpışma kontrolü sayısını azaltmanız gerekir. Evet, biliyorum. Şimdi bunun üzerinde duralım:

Herhangi bir optimizasyon olmadan ilk çarpışma kontrolü algoritmanız: bir seferde kaç kontrol yapacak? N nesne sayısı ise, bu n * (n-1) kontrolleri civarında olacaktır. Birçok nesne için (> 100) bu çok yavaş olacaktır.

Komşu kontrol yönteminiz çok daha hızlı olmayacak. Nesneleriniz statik değilse ve çok fazla hareket ediyorsa, oyun döngünüzde her nesne için bu komşu listesini oluşturmanız gerekir. Bu aslında ilk algoritmadan daha kötüdür, çünkü komşu listesini oluşturmak için n * (n-1) yapıyorsunuz ve daha sonra her bir nesneyi komşularından biriyle çarpışıp çarpışmadığını kontrol ediyorsunuz.

Oyun alanınızı bölümlere ayırmanız gerekir. Diyelim ki oyun alanınız 400x400 piksel genişliğinde. Bunu her biri 200x200 boyutunda 4 alt alana ayırabilir ve ait olduğu alt boşluklardan her bir nesneyi kontrol edebilirsiniz (bir nesne birden fazla alt boşluk içinde olabilir). O zaman sadece her alt alandaki nesnelerin aynı alt alandaki diğer nesnelerle çarpışıp çarpışmadığını kontrol etmeniz gerekir.

Bu yüzden çalışma zamanı maliyeti: n, bir önceki çalışma zamanı maliyetinden çok daha iyi olan 4 alt alan listesini + (n / 4) * ((n-1) / 4) oluşturmak için. Bu, alt boşlukları küçülterek daha da azaltılabilir (örn. 50x50).

Yani algoritmamız şu şekilde görünüyor:

for each (object in objects)
  check into which subspace the object belongs

for each (subspace in subspaces)
  for each (object in subspace)
    check object for collision with other objects in same subspace

Bu, döşeme verileri fikrinize biraz benzer. Ancak alt alanların karolarla aynı boyutta olması gerekmez.

Bunu bir dörtlü kullanarak daha da optimize etmek için son bir adım daha yapabiliriz. K alt uzayların sayısı olsun. Boşluk nesnesi listeleri oluşturmak için k * n kontrolleri yapıyoruz, bu da oyun dünyanızın büyüyüp büyümediğini kontrol ediyor.

Bu maliyeti azaltmak için dörtlü kullanıyoruz. Dörtlü, oyun alanımızı bölümlemenin başka bir yoludur. 400x400 alanımızı 64 50x50 alt alana bölmek ve şu anda 64 alt alandan oluşan her nesneyi kontrol etmek yerine, oyun alanı, oyun alanının (200x200) boyutunun yarısı olan 4 alt alana bölünür ve bu da daha küçük alt uzaylar (100x100), bu da yine 50x50 alt uzaylara bölünür. Bu bizim dörtlü.

Şimdi bir nesnenin hangi 50x50 alt uzayına ait olduğunu bilmek istiyorsak, 200x200 alt uzaylarından hangisine ait olduğunu kontrol ederiz. Sonra dört katımızda bir seviye daha derine iniyoruz ve az önce bulduğumuz 200x200 altuzayındaki 4 100x100 altuzayı kontrol ediyoruz. Nesnenin hangi 50x50 alt aralığına ait olduğunu öğreninceye kadar bu tekrarlanır. Peki şimdi kaç kontrol gerekliydi? Dört seviyenin her seviyesi için 4 (Bir nesnenin iki alt uzayın kenarında olabileceğini unutmayın). Bu nedenle, doğru 50x50 alt boşluğa bir nesne atamak için 4 * 3 kontrollere ihtiyacımız var. 64 kontrolden çok daha iyi.

Bu yüzden dört ağaç algoritmamızın alt boşluk listelerini oluşturmak için 4 * 3 * n kontrolüne ve ardından her nesnenin çarpışmasını kontrol etmek için k * (n / k) kontrolüne ihtiyaç vardır.


Bu çok açık ve anlaşılır bir awnser, çok teşekkürler! Bir nesnenin hangi altuzayında nasıl ele alınır? Altuzay, üzerindeki nesnenin diziler olarak kaydedildiği ve birbirlerine karşı kontrol edildiği bir nesne olarak mı ele alındı? Yoksa ana döngü içindeki X ve Y'yi kontrol ederek hangi altuzay olduğunu kontrol ediyor musunuz? Dizileri her zaman inşa etmek ve değiştirmek oldukça verimsiz görünüyor. Bu yüzden uygun yöntemi kullandığınızdan emin olmak istiyorum :) Nesnelerin boyutu değiştiğinde oluşan bir sorun da görebilirim. Sanırım en küçük alt uzay en büyük nesne kadar büyük olmalı?
omgnoseat

Yardımcı olmaktan memnunum :) Bir altuzay, içerdiği 4 altuzayı koruyan bir nesne olacaktır. Artık en küçük alt alan değil, nesnelerinizin bir listesini içerdiği için en küçük alt alan farklıdır. Güncelleme maliyeti göz önüne alındığında: altuzay ağacı oyun başlangıcında bir kez oluşturulur. Ana döngünün her döngüsünde, en küçük alt uzaylardaki nesne listeleri temizlenir ve tekrar doldurulur. Bu yüzden sadece liste ekleme / kaldırma gereklidir. Dizilerin değiştirilmesi gerekmez. En küçük alt alan birkaç oyun nesnesini içerecek kadar büyük olmalıdır. Ne kadar büyük oyununuza bağlıdır ve daha sonra değiştirilebilir.
Stephen

Teşekkürler, en küçük alt alanda gerçek nesneler arasındaki çarpışmaları da kontrol edeceğimizi unuttum, şimdi birden fazla nesneyi tutabilmesi mantıklı. Bir teste başladım ve güzel bir şekilde geliyor. Yaşadığım en büyük sorun, bir nesnenin hangi alt aralığa ait olduğunu tespit etmektir. Alt Xs ve Y değerleri alt döngü döngü devam, bu uygun bir yöntem mi?
omgnoseat

Birden fazla alt aralığa uzanan (yani konumu bir sınırın üzerinde veya yakınında olan) nesneleri nasıl ele alırsınız?
13'te mghicks

Basit: Yapmıyorum. Nesneler, her alt alanın sınırındaysa, birden çok alt uzayın parçası olabilir. Böylece bir nesne 4 adede kadar alt uzayın parçası olabilir. Ama bu azınlık.
Stephen
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.