Çok sayıda kare için Verimli Döşeme tabanlı çarpışma tespiti?


9

şu anda bir çini tabanlı oyun benim kendi çalışma üzerinde çalışıyorum (Terraria düşünüyorum, ama daha az fantastik (Bence bu bir kelime? Değilse özür dilerim)).

Her neyse, şu anda benim için büyük bir adım olan çarpışma tespiti çalışıyor (köşe vakaları için bile!). Bir sprite'ın bir bloktan geçmediğini görmek konusunda son derece sevindirici bir şey var. Ama sonra karşılaştırma yapma fikrim vardı. Kötü bir fikir.

1.000 kare, sorun değil. 10,000 karakter, 3 karakter için biraz laggy oldu. 100.000 kare (gerçekten büyük harita), 3 karakter için oynanamazdı.

Oyuncudan çok uzaktaki blokları, karakterleri, eşyaları vb. Düşünmek istemediğim bir sorun yaşıyorum, ancak sürekli olarak bellek içi olmayanları yüklemek istemiyorum.

İşte şimdiye kadar algoritmam, eleştirmekten çekinmeyin.

foreach (Block in level)
{
    if (distance from block to player > a specified amount)
        ignore this block;
    else
    {
        get the intersection depth between the two bounding boxes
        if (depth of intersection != Zero-vector)
        {
            check y size vs x size
            resolve on smallest axis
        }
    }
}

Dikkat edeceğiniz gibi, seviye boyutu büyüdüğünde, bu algoritmanın sırası N blokla büyür. Oyuncunun yakınında bile olmayan blokları bile düşünmek istemiyorum.

Ben belki bir (0,0) (mapWidth, mapHeight) bir liste yerine blok çift dizi kullanmak, kişinin pozisyonuna bağlı olarak bir tehlike bölgesi hesaplamak, örneğin, oyuncunun pozisyon (10, 20) ise düşünüyorum (0, 10) ila (20, 30) arasında görünecektir.

Herhangi bir düşünce ve düşünceniz harika, teşekkür ederim.


1
Ve stackexchange'e hoş geldiniz! :-) Tüm KG ve itibar sisteminin nasıl çalıştığını bilmiyorsanız SSS bölümünü okumayı unutmayın.
David Gouveia

Elbette bu karolar 16 x 16 pikselden daha büyüktür, 1920 x 1080'de 8.100 karo. Elbette hareketli varlıkların nerede olduğunu biliyorsunuz ve ızgarada sadece menzil içinde olabilecek karoları kontrol edebilirsiniz (biri 160 * 160 ise ve merkez karodaysa (12,12) sadece karolar arasında kontrol etmeniz gerekir (6 6) ve (18,18) toplam ~ 150 muhtemel karo için.). Elbette yerçekimi altındaki karolar sadece düşer ve bu yüzden sadece altındaki bir sonraki karoya bakmanız gerekir.
DampeS8N

Sizce 16x16 çok küçük mü? Karo genişliğine / yüksekliğine başvuran herhangi bir şey statik bir sabit olduğundan, karoların boyutunu değiştirmek benim için zor olmaz. Tek yapmam gereken onları Paint.NET'te büyütmek, ki bu daha fazla ayrıntı eklediğinden güzel.
Ross

Çarpışma kodunuzu paylaşmak ister misiniz? : /
ashes999

Yanıtlar:


7

Evet, doğru düşünüyorsun. Döşemeleri konuma göre dizine eklemenizi sağladığı için 2B döşemeler dizisi kullanmalısınız.

Block[,] level = new Block[width, height];

Ve oyuncu sadece çevresindeki taşlarla çarpışabileceğinden, yapmanız gereken çarpışma kontrolü sayısı çok azdır. Bu elbette oyuncunun boyutuna bağlıdır. Platformer örnek şöyle yapar:

int leftTile = (int)Math.Floor((float)characterBounds.Left / tileWidth);
int rightTile = (int)Math.Ceiling(((float)characterBounds.Right / tileWidth)) - 1;
int topTile = (int)Math.Floor((float)characterBounds.Top / tileHeight);
int bottomTile = (int)Math.Ceiling(((float)characterBounds.Bottom / tileHeight)) - 1;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {
        // Handle collisions with the tile level[x,y] just like you were doing!
    }
}

Hala sorun yaşıyorsanız örneği kontrol edin.


Bu çok güzel bir algoritma, Platformer örneğini bile duymamıştım (sahip olmalıydım, ama cehalet iddiasındayım). Teşekkür ederim!
Ross

@ Gerçekten mi? Çözümünüzün örneğe ne kadar benzediğine şaşıracaksınız. :-) Liste kısmı eksi, diğer her şey hemen hemen aynı (sınırlama kutuları kesişimi, kavşak derinliği almak, en küçük eksende çözmek).
David Gouveia

1
Ah adamım, sadece baktım. <2 gün önce bunu bilseydim! XNA'da yeniyim ama 2D grafiklerle uğraştım (sadece OpenGL, çok fazla oyun programlama değil). Kodlamaya ilk başlamadan önce daha fazla kaynağı kontrol etmeliyim sanırım.
Ross

1

Sanırım cevabım senin cevabın olurdu! ;-)

Oyuncu pozisyonunuz (ve boyutunuz) varsa, çevreleyen karoların endekslerini hesaplayabilirsiniz (sadece ayrıntılı olarak kontrol edilecek olanlar). Bu şekilde, haritanızın ne kadar büyük olduğu önemsiz olmalıdır, sadece oynatıcınızın gerçek boyutuna bağlıdır, böylece kontrol etmek için daha fazla fayans ortaya çıkar.

Eğer henüz yapmadıysanız, riemers.net adresindeki çarpışmalarla ilgili öğreticiyi kontrol edin .


Riemer'i duydum ama hiç bakmak için uğraşmadım, teşekkürler!
Ross

1

Çok sayıda çarpışma ile uğraşırken, genellikle bu çarpışmaları kontrol etmek için Quadtree veya Hashmap gibi daha gelişmiş bir yapı benimsemek istersiniz .

Fayans statik olduğundan bir Quadtree kullanmanızı öneririm. Dört ağaç dörtlüden oluşur. Her dörtlü dört dikdörtgenden oluşur ve bu dikdörtgenlerin her biri dörtlüdür. Bu, belirli bir boyuta kadar yinelemeli olarak devam eder. Her dörtlü, ekranın o bölgesinde yaşayan karoların bir listesini içerebilir. Bu şekilde, çarpışmaları kontrol ederken

  1. Çekleri yakın civardakilerle sınırlandırın
  2. Kontrolleri yalnızca hareket eden nesnelerle sınırla

Şimdi ekran dışı fayans bakmak bile istemiyorsanız o zaman gibi bir şey yapabilirdi

public bool CheckCollision(myPosition) {
    if(quadNodes.Count > 0) {
        // This is not a leaf, keep checking
        foreach(Quad node in quadNodes) {
            if(node.Position is insideViewport && nearPlayer)
                // Continue recursion
            }
        }
    }
    else {
        // This is a leaf, do checks
        foreach(Tile tile in tileList) {
            if(collision)
                return true;
        }
        return false;
    }
}

Hmm, Octrees'i 3D çarpışma tespitinde duydum, ancak 2D çarpışma tespiti için kullanılan gelişmiş bir Veri Yapısı görmedim. Çok teşekkür ederim!
Ross

1
Oyunu (Terraria olduğunu varsayarak) eşit aralıklı fayanslardan oluştuğu için, bir ızgara kullanmak bir dörtlüden çok daha kolay ve hızlı olacaktır. Bir dörtlü, bir ızgaranın sığması zor olan ve her şeyin keyfi boyutta olduğu daha karmaşık dünyalar için daha iyi çalışır.
David Gouveia

1
Karakter boyutlarına kadar bile tamamen ızgara tabanlı bir oyunsa haklısınız. Terraria'da bir ızgara formatına kolayca sığmayan canavarların da olduğunu biliyorum. Temel dünyanın fayanslardan oluştuğu varsayımıyla koşuyordum, ancak diğer nesneler farklı olurdu ve başka bir tane inşa etmekten kaçınmak için onları benzer bir yapıda saklayabilirlerdi. Ben fayans için bir ızgara kullanabilirsiniz varsayalım sonra diğer keyfi nesneler için farklı bir yapı (gerekirse).
Mike Cluck

1
Ben önermek üzereydim :) Izgara arazi ile çarpışmalar işlemek için kullanılırken, bir dörtlü-nesneler arası çarpışmalar için kullanılabilir.
David Gouveia

Doğru. Şu anda her sınırlayıcı kutunun 2 ^ güç boyutu vardır. Bu, çarpışma tespiti için bulmamı kolaylaştırır. Şimdilik benim için bir ızgara olurdu.
Ross
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.