Potansiyel olarak sonsuz 2B harita verilerini depolamanın bir yolu?


29

Şu anda 100'e 100 karolu topakları kaldırabilen bir 2D platformum var, öbek koordinatları uzun süre olarak saklanıyor, bu yüzden haritalar tek sınırı (maxlong * maxlong). Bütün varlık pozisyonları vs.

Karşılaştığım sorun, binlerce dosyaya ihtiyaç duymadan bu parçalara nasıl depolanıp erişileceği. Her şeyi bir seferde açması gerekmeyen, tercihen hızlı ve düşük maliyetli bir arşiv formatı için bir fikriniz var mı?


2
Daha fazla ilham almak için arayabileceğiniz bazı veri yapıları seyrek matrisler ve (çok düzeyli) sayfa tablolarıdır .
Andrew Russell

Düşük öncelik: "Uzun" veri türünün 32 bit mi, yoksa 64 bit mi olduğunu açıklayabilir misiniz?
Randolf Richardson

2
@Randolf, bunun C # olduğu göz önüne alındığında, muhtemelen long64-bit olan C # anlamına gelir (bu yüzden maksimumdur Int64.MaxValue).
Andrew Russell

Yanıtlar:


17

Oyununuz için özel bir harita formatı oluşturun. Düşündüğünden daha kolay. Sadece BinaryWriter sınıfını kullanın. Öncelikle başlığı bir kaç inç ya da kullanıcı adıyla yazınız. Başlığa dahil edilecek bilgiler:

  • Sihirli dizge / sihirli dosya sayısı.
  • Bu dosyada açıklanan parçaların başlangıç ​​/ bitiş / boyut

ve ayrıca (ve burada performansın kritik kısmı geliyor

  • Dosyanın içindeki başlangıç ​​konumunu açıklayan ints. Yani belirli parçaları aramak zorunda değilsiniz.

Yukarıdaki yöntemle, dosya içeriğinizin bir dizinini oluşturabilir (bir tür açıklama (bölge / öbek için kullanıcı tarafından belirtilen bir ad veya yalnızca koordinatlar) ve ikinci bir değer olarak dosyadaki konumu oluşturabilirsiniz.

Ardından, belirli bir yığın yüklemek istediğinizde, dizinin içinde arama yapmanız gerekir. Pozisyonu aldığınızda sadece fileStream.Position = PositionOfChunkFromIndex değerini ayarlayın ve yükleyebilirsiniz.

Her şey, dosya içeriğinin tasarımı ile ilgili, dosyanın içeriğini en verimli şekilde tanımlayan başlık.

Sadece dosyalarınızı oluşturduğunuz özel bir uzantı ile kaydedin.

BONUS: BZip2 sıkıştırmasını dosyanın belirli bölgelerine / içeriğinin tamamına (başlık değil!) Ekleyin, böylece çok küçük bir bellek alanı için dosyadan belirli parçaları açabilirsiniz.


12
Anında, bu dosyayı anında değiştirecekseniz, sabit boyutlu veya harici bir başlık / dizin isteyeceğinize dikkat edin; tüm dosya (ofsetlerin değişmesi nedeniyle).
Andrew Russell

Bu noktada, sadece bir flatfile veritabanı uygulamıyor musunuz?
Ape-inago

13

Benzer bir sorunla karşılaştım ve verileri işlemek için kendi yapımı yaratmaya karar verdim. Gevşek bir dörtlü üzerinde temellenir, ancak her yöne sınırsız (en az bir Int kadar büyük) genişletilebilirliği vardır. Minecraft'ın yaptığı gibi, merkezi bir noktadan genişleyen grid tabanlı verileri işlemek için tasarlanmıştır. Bellekte yer verimli ve çok hızlı.

Her düğüm için minimum bir büyüklük belirleyebilirsiniz (7'nin büyüklüğü 128x128 olur) ve herhangi bir düğüm, alt düğümlerinin belirli bir yüzdesini doldurduktan sonra, kendisini otomatik olarak iki boyutlu bir diziye düzleştirir. Bu, çok yoğun nüfuslu bir kısmın (örneğin, tamamen araştırılmış bir kıtanın) bir dizinin performansına sahip olacağı (çok hızlı) ancak seyrek nüfuslu bir kısmın (örneğin, biri yukarı ve aşağı dolaşan ancak iç kesimleri keşfetmeyen bir kıyı şeridi) göstereceği anlamına gelir. iyi performans ve düşük bellek kullanımı var.

Kodumu burada bulabilirsiniz . Kod tamamlandı, test edildi (ünite ve yük testleri) ve oldukça optimize edildi. Bununla birlikte, iç işler henüz yeterince belgelenmemiştir, ancak tüm kamu yöntemleri bu yüzden kullanılabilir olmalıdır. Herhangi biri denemeye karar verirse, sorularınız veya yorumlarınız için benimle temas kurmaktan çekinmeyin.

Verileri bir dosyaya depolamak için henüz kullanmadım, ancak bu ilginç bir problem ve bundan sonra başa çıkabilirim.


Yani bu temelde genişletilebilir bir ağaç, değil mi? Neyi kaçırıyorum?
kaoD

2
Genişletilebilir bir ağaç üzerindeki en büyük gelişme, yoğun şekilde doldurulmuş (varsayılan olarak% 70) ağacın belirli ağaç düğümlerini, ağaçlar gibi yapılandırılmaları yerine 2B dizilere 'yassılaştırması' dır. Bu, sonsuz bir dizinin (sonsuz) boyutu olmadan dizi aramasının hızını verir.
dlras2

Hem yaprak hem de iç düğümler, değil mi? İlginç bir fikir, iyi sonuçlar verebilir, buna ihtiyacım olursa denerim. Btw, kodu ve hızlı cevabı veren +1! Oh, ve birim testi de yaptım, (ne yazık ki) bunu kişisel projelerimde asla yapmam :)
kaoD

İşimde herhangi bir birim testi yapmıyoruz, bu yüzden ne yazık ki isyan etme biçimim .. Bunun için bir demo uygulaması yaptım. Günler çok iyi geliyor, ben de buraya postalayacağım. Gördüğünüz zaman çok daha anlamlı olur.
dlras2

1
Görüşünü kaybettim, özür dilerim! Hala onu temizletmek isterdim, ama yavaş yavaş sınıf ve ev ödevi arasındaki bazı kodları elden geçiriyorum, bu yüzden bir süre olmayacak. Şimdilik, eski, hoş olmayan demo burada: j.mp/qIwKYt Hoş olmayanlar tarafından kısmen açıklanması gereken bir anlam ifade ediyor, bu nedenle README'yi okumayı ve burada soru sormaktan çekinmeyin veya e-posta yoluyla.
dlras2

3

Bunun yerine bir veritabanı kullanabilirsiniz - PostgreSQL, X ve Y koordinatlarında bulunan bu tür veriler için optimize edilmiş bazı özel indeksleme özelliklerine sahiptir. Döndürülen verilerin kare veya dikdörtgen şekilli bir alan yerine belirli bir yarıçap içinde olduğunu da belirleyebilirsiniz.

  PostgreSQL (ücretsiz ve açık kaynak)
  http://www.postgresql.org/

Başka veritabanları da var ve müşteri tarafı için, kendi başlarına çalışabilecekleri (oyun müşteri uygulamanız tarafından başlatılan) veya bir kod kütüphanesinin parçası olarak dahil edilebilecekleri için buna daha uygun bazı türler bulabilirsiniz. "Sadece kullanabileceğini" Bunun avantajı, bir endeksleme şeması tasarlamak zorunda olmamanızdır çünkü çoğu SQL veritabanı motoru zaten bunu oldukça iyi yapar.

Veri tabanı yaklaşımının bir avantajı, topaklarınızı daha küçük hale getirmeniz (ya da topakları tamamen ortadan kaldırmanız ve doğrudan kiremit kullanmanızdır, ancak tasarımınıza bağlı olarak en az küçük topakların / grupların kullanımı en verimli olabilir). ve sonra görüntülenebilir olandan daha geniş bir alana getirmek için SQL sorgusunu kullanın. Yakındaki görülemeyen alanları üst üste bindirmek için önceden yükleme yapılarak, fayanslar oyuncu karakterlerini hareket ettirmeden önce hazırlanabilir , böylece daha iyi (umarım daha pürüzsüz) bir oyun deneyimi elde edilir.

Bazı oyunların, Ashen Empires gibi, ilk defa edindikten sonra yerel sabit sürücüdeki harita verilerinin bir "önbelleğini" tuttuğunu fark ettim (şüphesiz ağ giriş / çıkışlarını azaltmak için budur):

  Ashen Empires (oynamak ücretsiz, güzel 2D uygulama)
  http://www.ashenempires.com/

Her bir öbek / karo ile birlikte "son güncelleme" zaman damgasını takip etmek de yararlı olacaktır, çünkü yerel olarak depolanmış verilerin bulunduğu yerlerde, SQL sorgusu ek bir "WHERE timestamp_column> $ local_timestamp" yan tümcesi içerebilir, böylece sadece güncellenmiş parçalar / karolar elde edilebilir. indirilen (bunun gibi bant genişliğinden tasarruf etmenin iki avantajı, düşük bağlantı maliyetleridir ve oyuncularınız için daha az gecikmedir, ki oyununuz popülerleştiğinde daha belirgin hale gelir).

Ashen Empires'dan bir ekran görüntüsü (birkaç karakter yerel bir bankada ve yerdeki kemiklere bakıldığında birkaç iskelet canavarı içeri girmiş olmalı ve yerel kasabanın muhafızları tarafından katledilmiş gibi görünüyor):

enter image description here


2

Saklamayın ve bunlara erişmeyin, oyuncunun haritadaki değişikliklerinin yanı sıra yalnızca gerekli rastgele tohumları saklayın. Daha sonra çalışma zamanında gerekli bölümleri oluşturun (üretim algoritmanızı çalıştırın, ardından oyuncunun değişikliklerini uygulayın). Doğru ve tutarlı üretim prosedürü ile elde edilen harita her zaman aynı başlangıç ​​tohumu için aynı olacaktır.

Teorik olarak bu şekilde çok küçük bir dosyaya kaydedecek tam anlamıyla sonsuz harita yapabilirsiniz.


@Josh Petrie, yazımdaki önemli ve mükemmel dil / üslup düzeltmeleri için teşekkürler. pity düzenlemeyi kaldıramıyorum :-D
sh code

1

Parçaları (dünyadaki bir çeşit “alt kıtalar / ülke”) bölümlere ayırmanın bir yolu var mı? Belki de hafızada bir yığın olması için hangi büyük dosyanın / alt kısmının hangi büyük dosyayı yüklemeniz gerektiğini hızlı bir şekilde bulmanıza izin veren bir tür dizin dosyalarına sahip olabilirsiniz.


there is always a way you can partition chunks. ALWAYS. whether they're visible to the player/relevant to the rest of the system or not, there's always a way to partition world data to chunks, usually in multiple different ways.
sh code

0

You could take the idea from Minecraft. Originally they had a file per chunk. Now they use the MCRegion format, which groups chunks into 32x32 areas and stores one of those per file.

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.