Tüm harita tasarımı ve fayans dizisi tasarımı karşılaştırması


11

Her zamanki zindan / kasaba haritaları (önceden oluşturulmuş) özellikli bir 2D RPG üzerinde çalışıyorum.

Haritaları yapmak için birleştireceğim fayans kullanıyorum. Orijinal planım, daha sonra harita olarak kullanabileceğim daha büyük bir resim elde etmek için Photoshop'u veya başka bir grafik programını kullanarak döşemeleri birleştirmekti.

Ancak, insanların motorda haritalarını oluşturmak için dizileri nasıl kullandıklarından bahsettikleri birkaç yerde okudum (böylece motorunuza bir x karo dizisi verirsiniz ve bunları bir harita olarak birleştirirsiniz). Nasıl yapıldığını anlayabiliyorum, ancak uygulanması çok daha karmaşık görünüyor ve bariz avantajları göremiyorum.

En yaygın yöntem nedir ve her birinin avantajları / dezavantajları nelerdir?


1
Ana sorun hafızadır. Bir kez 1080p ekranı dolduran bir doku yaklaşık 60mb'dir. Böylece bir görüntü piksel başına int kullanır, bir döşemede int (piksel / (tilesize * tilesize)) kullanılır. Eğer karolar 32,32 ise, karoları bir piksele kullanarak 1024 kat daha büyük bir haritayı temsil edebilirsiniz. Ayrıca doku takas süreleri vb bu kadar bellek iterek incitecek ...
ClassicThunder

Yanıtlar:


19

Öncelikle, 2D RPG'lerin kalbime yakın ve sevgili olduğunu ve eski DX7 VB6 MORPG motorlarıyla çalıştığını söyleyeyim (gülme, 8 yıl önceydi, şimdi :-)) beni ilk kez oyun geliştirmeyle ilgilendirdi . Son zamanlarda, XNA kullanmak için bu motorlardan birinde üzerinde çalıştığım bir oyunu dönüştürmeye başladım.

Bununla birlikte, tavsiyem, haritanız için katman içeren karo tabanlı bir yapı kullanmanızdır. Kullandığınız herhangi bir grafik API'sında yükleyebileceğiniz dokuların boyutu için bir sınırınız olacaktır. Grafik kartı doku bellek sınırlarından bahsetmiyorum bile. Dolayısıyla, bunu göz önünde bulundurarak, yalnızca belleğe yüklediğiniz dokuların miktarını ve boyutunu en aza indirirken aynı zamanda kullanıcının sabit diskindeki ve yükleme sürelerindeki varlıklarınızın boyutunu da azaltırken, haritalarınızın boyutunu en üst düzeye çıkarmak istiyorsanız, kesinlikle fayans ile gitmek isteyeceksiniz.

Uygulamaya gelince, burada GameDev.SE ve blogumdaki (her ikisi de aşağıda bağlantılıdır) birkaç soruda nasıl ele aldığım konusunda ayrıntılı bir şekilde ele aldım ve bu tam olarak sorduğunuz şey değil, bu yüzden sadece burada temelleri ele alalım. Ayrıca, önceden oluşturulmuş birkaç büyük görüntüyü yüklemede onları yararlı kılan karoların özelliklerini de not edeceğim. Bir şey net değilse bana bildirin.

  1. Yapmanız gereken ilk şey bir karo sayfası oluşturmaktır. Bu, bir kareye hizalanmış tüm karolarınızı içeren büyük bir görüntüdür. Bu (ve belki de karo sayısına bağlı olarak ekstra bir tane) yüklemeniz gereken tek şey olacaktır. Sadece 1 resim! Harita başına 1 veya oyundaki her kutucuk için bir tane yükleyebilirsiniz; hangi kuruluş sizin için çalışıyorsa.
  2. Ardından, bu "sayfayı" nasıl alabileceğinizi ve her döşemeyi bir sayıya nasıl çevirebileceğinizi anlamanız gerekir. Bu basit bir matematik ile oldukça basittir. Buradaki bölümün tamsayı bölüm olduğunu unutmayın , bu nedenle ondalık basamaklar düşürülür (veya isterseniz yuvarlanır). Hücreleri koordinatlara ve geri dönüştürmek.
  3. Tamam, şimdi döşeme sayfasını bir dizi hücreye (sayılar) böltüğünüze göre, bu sayıları alıp istediğiniz herhangi bir kaba takabilirsiniz. Kolaylık olması için, sadece bir 2D dizi kullanabilirsiniz.

    int[,] mapTiles = new int[100,100]; //Map is 100x100 tiles without much overhead
  4. Sonra, onları çizmek istiyorsunuz. Bunu daha verimli hale getirmenin yollarından biri (harita boyutuna bağlı olarak) yalnızca kameranın görüntülemekte olduğu hücreleri hesaplamak ve bunlar arasında döngü yapmaktır. Bunu, kameranın sol üst ( tl) ve sağ alt ( br) köşelerinin harita döşemesi dizi koordinatlarını getirerek yapabilirsiniz . Daha sonra bunları çizmek için tl.X to br.Xve iç içe bir döngü içinde ve arasında döngü yapın tl.Y to br.Y. Aşağıdaki örnek kod:

    for (int x = tl.X; x <= br.X;x++) {
        for (int y = tl.Y; y <= br.Y;y++) {
            //Assuming tileset setup from image
            Vector2 tilesetCoordinate = new Vector2((mapTiles[x,y] % 8) * 32,(mapTiles[x,y] / 8) * 32);
            //Draw 32x32 tile using tilesetCoordinate as the source x,y
        }
    }
    
  5. İkramiye! Karo motorunun temelleri budur. 1000x1000'lik bir haritanın bile fazla bir yükü olmadan kolay olduğunu görebilirsiniz. Ayrıca, 255'ten az kutunuz varsa, belleği hücre başına 3 bayt azaltan bir bayt dizisi kullanabilirsiniz. Bir bayt çok küçükse, ihtiyaçlarınız için muhtemelen bir ushort yeterli olacaktır.

Not: Dünya koordinatları kavramını (kameranızın konumunun temel alacağı şey) bıraktım, çünkü bence bu cevabın kapsamı dışında. Bunu GameDev.SE'de buradan okuyabilirsiniz.

Döşeme Motoru Kaynaklarım
Not: Bunların tümü XNA'yı hedefliyor, ancak hemen hemen her şey için geçerli - sadece çizim çağrılarını değiştirmeniz gerekiyor.

  • Bu soruya cevabım , harita hücrelerinin ve katmanımın oyunumda nasıl ele aldığımı özetliyor. (Bkz. Üçüncü bağlantı.)
  • Bu soruya verdiğim yanıt , verileri ikili biçimde nasıl depoladığımı açıklıyor.
  • Bu , üzerinde çalıştığım oyunun gelişimi hakkında ilk (iyi, teknik olarak ikinci, ama ilk "teknik") blog yazısı. Tüm seri piksel gölgelendiriciler, aydınlatma, fayans davranışları, hareket ve tüm bu eğlenceli şeyler hakkında bilgi içerir. Aslında, yukarıda yayınladığım ilk bağlantıya cevabımın içeriğini içerecek şekilde yazıyı güncelledim, bu yüzden onu okumak isteyebilirsiniz (bir şeyler ekledim). Herhangi bir sorunuz varsa, buraya veya buraya bir yorum bırakabilirsiniz. Size yardımcı olmaktan memnuniyet duyarız.

Diğer Döşeme Motoru Kaynakları

  • Bu sitedeki karo motoru öğreticisi bana haritalarımı oluşturmak için kullandığım temeli verdi.
  • Aslında bu video eğitimlerini henüz izlemedim çünkü zamanım olmadı, ancak muhtemelen yardımcı oluyorlar. :) XNA kullanıyorsanız, bunlar eski olabilir.
  • Bu sitede (bence) yukarıdaki videolara dayanan bazı öğreticiler var. Kontrol etmeye değer olabilir.

Waow, bu istediğimden iki kat daha fazla bilgi ve
sormadığım

@Mikalichov - Yardımcı olabileceğim için mutluyum! :)
Richard Marskell - Drackir

Genellikle bir 2D dizisi ile ilk boyutu Y'niz, diğerini X'iniz olarak kullanmak istersiniz. Bellekte bir dizi sırayla 0,0-i sonra 1,0-i olacaktır. X ilk tavukla iç içe döngüler yaparsanız, sıralı bir okuma yolunu izlemek yerine bellekte ileri geri atlıyorsunuz demektir. Daima (y) sonra da (x) için.
Brett W

@BrettW - Geçerli bir nokta. Teşekkürler. 2D dizilerin .Net'te nasıl saklandığını merak ettim (Satır-büyük sipariş. Bugün yeni bir şey öğrendim! :-)). Ancak, kodumu güncelledikten sonra, sadece anahtarlanan değişkenlerle, tanımladığınızla tamamen aynı olduğunu fark ettim. Fark, karoların hangi sırada çizildiğidir. Mevcut örnek kodum yukarıdan aşağıya, soldan sağa çekerken, açıkladığınız şey soldan sağa, yukarıdan aşağıya çekiyordu. Bu nedenle, basitlik adına, orijinaline geri döndürmeye karar verdim. :-)
Richard Marskell - Drackir

6

Hem karo esaslı sistemler hem de statik model / doku sistemi bir dünyayı temsil etmek için kullanılabilir ve her birinin farklı güçleri vardır. Birinin diğerinden daha iyi olup olmadığı parçaları nasıl kullandığınıza ve beceri ve ihtiyaçlarınız için en iyi olana bağlıdır.

Her iki sistemin ayrı ayrı veya birlikte kullanılabileceği söylenir.

Standart bir karo esaslı sistem aşağıdaki güçlü yönlere sahiptir:

  • Fayansların 2D 2D Dizisi
  • Her karonun tek bir malzemesi vardır
    • Bu malzeme tek bir doku, çoklu veya etrafındaki fayanslardan harmanlanmış olabilir
    • Varlık oluşturma ve yeniden çalışmayı azaltarak bu türdeki tüm karolar için dokuları yeniden kullanabilir
  • Her karo fena olabilir veya olmayabilir (çarpışma tespiti)
  • Haritanın bölümlerini oluşturmak ve tanımlamak kolay
    • Karakter konumu ve harita konumu mutlak koordinatlardır
    • Ekran bölgesi için ilgili kutucuklar arasında geçiş yapmak kolaydır

Döşemelerin dezavantajı, bu döşemeye dayalı verileri oluşturmak için bir sistem oluşturmanız gerektiğidir. Döşeme olarak her pikseli kullanan bir görüntü oluşturabilir, böylece 2B dizinizi bir dokudan oluşturabilirsiniz. Ayrıca özel bir biçim de oluşturabilirsiniz. Bitflags kullanarak, döşeme başına çok sayıda veriyi oldukça küçük bir alanda saklayabilirsiniz.

Çoğu insanın fayans yapmasının başlıca nedeni, küçük varlıklar oluşturmalarına ve bunları yeniden kullanmalarına izin vermesidir. Bu küçük parçalar çok daha büyük bir resim oluşturmak için izin verir. Küçük bir değişiklik yapmak için tüm dünya haritasını değiştirmediğiniz için yeniden çalışmayı azaltır. Örneğin, tüm çimlerin gölgesini değiştirmek istiyorsanız. Büyük bir görüntüde tüm çimleri yeniden boyamanız gerekir. Bir fayans sisteminde çim fayans (lar) ını güncellemeniz yeterlidir.

Hepsi bir arada, kendinizi büyük bir grafik haritadan ziyade kiremit tabanlı bir sistemle çok daha az yeniden çalışma yaparken bulacaksınız. Zemin haritanız için kullanmasanız bile çarpışma için kiremit tabanlı bir sistem kullanabilirsiniz. Bir döşemeyi dahili olarak kullanmanız, ortamdaki nesneleri temsil etmek için modelleri kullanamayacağınız anlamına gelmez.

Kod örnekleri sunmak için ortamınız / motorunuz / diliniz hakkında daha fazla bilgi sağlamanız gerekir.


Teşekkürler! C # altında çalışıyorum ve Final Fantasy 6'nın (veya temelde çoğu Square SNES RPG) benzer (ama daha az yetenekli) bir versiyonunu kullanıyorum, bu yüzden yer karoları VE yapı karoları (yani evler). Benim en büyük endişem, "orada bir çim köşesi var, sonra üç düz yatay, sonra bir ev köşesi, sonra ..", saatlerce kontrol etmeden 2D dizisini nasıl oluşturacağımı görmemem. yol.
Cristol.GdM

Görünüşe göre Richard sizi kodla ilgili olarak ele alıyor. Şahsen tiletiplerin bir numaralandırmasını ve döşemenin değerini tanımlamak için bitflags kullanırdım. Bu, ortalama bir tamsayıda 32+ değeri depolamanızı sağlar. Ayrıca her kutucuk için birden fazla bayrak saklayabilirsiniz. Yani ayrı değişkenler olmadan Grass = true, Wall = true, Collision = true vb. Diyebilirsiniz. Ardından, belirli bir harita bölgesinin grafikleri için döşeme sayfasını belirleyen "temalar" atarsınız.
Brett W

3

Haritayı çizme: Fayanslar motorda kolaydır, çünkü harita dev bir karo endeksi dizisi olarak temsil edilebilir. Çizim kodu sadece iç içe bir döngüdür:

for i from min_x to max_x:
    for j from min_y to max_y:
        Draw(Tiles[i][j], getPosition(i,j))

Büyük haritalar için, tüm harita için büyük bir bitmap görüntüsü bellekte çok yer kaplayabilir ve bir grafik kartının tek bir görüntü boyutu için desteklediğinden daha büyük olabilir. Ancak kutucuklarla ilgili herhangi bir sorun yaşamayacaksınız, çünkü grafik belleğini her kutucuk için yalnızca bir kez ayırıyorsunuz (ya da toplam bir tane, en iyisi, hepsi tek bir sayfadaysa)

Döşeme bilgilerini örneğin çarpışmalar için tekrar kullanmak da kolaydır. örneğin, arazi döşemesini karakterin hareketli grafiğinin sol üst köşesine almak için:

let x,y = character.position
let i,j = getTileIndex(x,y) // <- getTileIndex is the opposite function of getPosition
let tile = Tiles[i][j]

Kayalar / ağaçlar vb. Çarpışmalarını kontrol etmeniz gerektiğini varsayalım. Döşemeyi (karakter konumu + karakter hareketli karakter boyutu + geçerli yön) konumuna getirebilir ve yürünebilir olarak işaretlenip işaretlenemeyeceğini kontrol edebilirsiniz.

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.