तिलमप डेटा स्टोर करने का एक अच्छा तरीका क्या है?


13

मैं कुछ यूनी दोस्तों के साथ एक 2D प्लेटफार्म विकसित कर रहा हूं। हमने इसे XNA प्लेटफ़ॉर्मर स्टार्टर किट पर आधारित किया है जो टाइल मैप को संग्रहीत करने के लिए .txt फ़ाइलों का उपयोग करता है। हालांकि यह सरल है, यह हमें स्तर के डिजाइन के साथ पर्याप्त नियंत्रण और लचीलापन नहीं देता है। कुछ उदाहरण: सामग्री की कई परतों के लिए कई फ़ाइलों की आवश्यकता होती है, प्रत्येक ऑब्जेक्ट ग्रिड पर तय किया जाता है, वस्तुओं के रोटेशन, सीमित संख्या में वर्ण आदि की अनुमति नहीं देता है, इसलिए मैं स्तर के डेटा को स्टोर करने के तरीके में कुछ शोध कर रहा हूं। और नक्शा फ़ाइल।

यह केवल टाइल मैप्स के फाइल सिस्टम स्टोरेज की चिंता करता है, न कि खेल द्वारा उपयोग किए जाने वाले डेटा स्ट्रक्चर का, जबकि यह चल रहा होता है। टाइल मानचित्र को 2 डी सरणी में लोड किया गया है, इसलिए यह सवाल है कि किस स्रोत से सरणी को भरना है।

DB के लिए तर्क: अपने दृष्टिकोण से मैं टाइल डेटा को संग्रहीत करने के लिए डेटाबेस का उपयोग करके डेटा की कम अतिरेक को देखता हूं। समान विशेषताओं वाली समान एक्स, वाई स्थिति में टाइलें स्तर से स्तर तक पुन: उपयोग की जा सकती हैं। ऐसा लगता है कि डेटाबेस से एक विशेष स्तर में उपयोग की जाने वाली सभी टाइलों को पुनः प्राप्त करने के लिए एक विधि लिखना काफी सरल होगा।

JSON / XML के लिए रीज़निंग: दृश्यमान रूप से संपादन योग्य फ़ाइलें, बदलावों को SVN के माध्यम से बहुत आसान तरीके से ट्रैक किया जा सकता है। लेकिन बार-बार सामग्री आती है।

क्या अन्य की तुलना में या तो कोई कमियां हैं (लोड समय, एक्सेस टाइम, मेमोरी आदि)? और आमतौर पर उद्योग में क्या उपयोग किया जाता है?

वर्तमान में फ़ाइल इस तरह दिखती है:

....................
....................
....................
....................
....................
....................
....................
.........GGG........
.........###........
....................
....GGG.......GGG...
....###.......###...
....................
.1................X.
####################

1 - प्लेयर स्टार्ट पॉइंट, एक्स - लेवल एक्जिट,। - खाली स्थान, # - प्लेटफार्म, जी - जेम


2
क्या मौजूदा "प्रारूप" आप उपयोग कर रहे हैं? सिर्फ "टेक्स्ट फाइल्स" कहने का मतलब है कि आप बाइनरी डेटा को सेव नहीं कर रहे हैं। जब आप कहते हैं कि "पर्याप्त नियंत्रण और लचीलापन नहीं", क्या, विशेष रूप से आप में चल रही समस्याएं हैं? XML और SQLite के बीच टॉसअप क्यों? वह उत्तर निर्धारित करेगा। blog.stackoverflow.com/2011/08/gorilla-vs-shark
Tetrad

मैं JSON का विकल्प चुनूंगा क्योंकि यह अधिक पठनीय है।
डेन

3
लोग इन चीजों के लिए SQLite का उपयोग करने के बारे में क्यों सोचते हैं? यह एक संबंधपरक डेटाबेस है ; लोग क्यों सोचते हैं कि एक संबंधपरक डेटाबेस एक अच्छा फ़ाइल प्रारूप बनाता है?
निकोल बोलस

1
@StephenTierney: यह सवाल अचानक XML बनाम SQLite से JSON बनाम किसी भी तरह के डेटाबेस में क्यों चला गया? मेरा सवाल विशेष रूप से यह सिर्फ क्यों नहीं है, "तिलमप डेटा स्टोर करने का एक अच्छा तरीका क्या है?" यह एक्स बनाम वाई प्रश्न मनमाना और अर्थहीन है।
निकोल बोलस

1
@ किलोटन: लेकिन यह बहुत अच्छी तरह से काम नहीं करता है। इसे संपादित करना अविश्वसनीय रूप से कठिन है, क्योंकि आप केवल SQL कमांड के माध्यम से डेटाबेस को संपादित कर सकते हैं। यह पढ़ना मुश्किल है, क्योंकि तालिकाओं वास्तव में एक तिलमाप को देखने और क्या हो रहा है की समझ रखने का एक प्रभावी तरीका नहीं है। और जब यह लुकअप कर सकता है, तो लुकअप प्रक्रिया अविश्वसनीय रूप से ओवर-कंप्लिकेटेड है। कुछ काम करना महत्वपूर्ण है, लेकिन अगर यह वास्तव में खेल को विकसित करने की प्रक्रिया को बहुत कठिन बना रहा है, तो यह छोटा रास्ता लेने के लिए इसके लायक नहीं है।
निकोल बोलस

जवाबों:


14

तो अपने अद्यतन किए गए प्रश्न के माध्यम से पढ़ते हुए, ऐसा लगता है कि आप डिस्क पर "अनावश्यक डेटा" के बारे में सबसे अधिक चिंतित हैं, लोड समय और उद्योग द्वारा उपयोग किए जाने के बारे में कुछ माध्यमिक चिंताओं के साथ।

सबसे पहले, आप अनावश्यक डेटा के बारे में चिंतित क्यों हैं? एक्सएमएल जैसे फूला हुआ प्रारूप के लिए भी, संपीड़न को लागू करने और अपने स्तरों के आकार को नीचे लाने के लिए यह बहुत तुच्छ होगा। आपको अपने स्तर के डेटा की तुलना में बनावट या ध्वनियों के साथ जगह लेने की अधिक संभावना है।

दूसरा, एक द्विआधारी प्रारूप पाठ-आधारित एक की तुलना में तेजी से लोड होने की संभावना से अधिक है जिसे आपको पार्स करना है। संदेह है कि अगर आप इसे सिर्फ स्मृति में छोड़ सकते हैं और आपकी डेटा संरचनाएं वहीं हैं। हालाँकि, इसके कुछ डाउनसाइड हैं। एक के लिए, बाइनरी फ़ाइलों को डीबग करना असंभव है (विशेषकर सामग्री निर्माण लोगों के लिए)। आप उन्हें अलग या संस्करणित नहीं कर सकते। लेकिन वे छोटे होंगे, और तेजी से लोड होंगे।

कुछ इंजन क्या करते हैं (और क्या मैं एक आदर्श स्थिति पर विचार करता हूं) दो लोडिंग पथों को लागू करता है। विकास के लिए, आप किसी प्रकार के पाठ-आधारित प्रारूप का उपयोग करते हैं। यह वास्तव में कोई फर्क नहीं पड़ता कि आप किस विशिष्ट प्रारूप का उपयोग करते हैं, जब तक आप एक पुस्तकालय का उपयोग करते हैं जो ठोस है। रिलीज के लिए, आप एक बाइनरी लोड करने के लिए स्विच करते हैं (छोटे, तेज लोडिंग, संभवतः डिबग संस्थाओं से छीन लिया गया) संस्करण। स्तरों को संपादित करने के लिए आपके उपकरण दोनों को बाहर थूकते हैं। यह सिर्फ एक फ़ाइल प्रारूप की तुलना में बहुत अधिक काम है, लेकिन आप दोनों दुनिया के सर्वश्रेष्ठ प्राप्त कर सकते हैं।

यह सब कहा जा रहा है, मुझे लगता है कि आप बंदूक को थोड़ा उछाल रहे हैं।

इन समस्याओं के लिए एक चरण हमेशा उस समस्या का वर्णन करें जो आप पूरी तरह से चला रहे हैं। यदि आप जानते हैं कि आपको किस डेटा की आवश्यकता है, तो आप जानते हैं कि आपको किस डेटा को संग्रहीत करने की आवश्यकता है। वहाँ से यह एक परीक्षण योग्य अनुकूलन प्रश्न है।

यदि आपके पास परीक्षण करने के लिए उपयोग का मामला है, तो आप जो कुछ भी महत्वपूर्ण मानते हैं (लोडिंग समय, मेमोरी उपयोग, डिस्क आकार, आदि) को मापने के लिए डेटा को संग्रहीत / लोड करने के कुछ अलग तरीकों का परीक्षण कर सकते हैं। किसी भी जानने के बिना, यह अधिक विशिष्ट होना कठिन है।


9
  • XML: हाथ से संपादित करना आसान है लेकिन एक बार जब आप बहुत अधिक डेटा लोड करना शुरू करते हैं, तो यह धीमा हो जाता है।
  • SQLite: यह बेहतर हो सकता है यदि आप एक ही बार में या बहुत छोटे डेटा को पुनः प्राप्त करना चाहते हैं। हालाँकि, जब तक आप अपने खेल में कहीं और इसका उपयोग कर रहे हैं, मुझे लगता है कि यह आपके नक्शे के लिए ओवरकिल है (और शायद अधूरा है)।

मेरी सिफारिश एक कस्टम बाइनरी फ़ाइल प्रारूप का उपयोग करना है। अपने खेल के साथ, मेरे पास बस एक SaveMapतरीका है जो एक क्षेत्र का उपयोग करता है और प्रत्येक क्षेत्र को बचाता है BinaryWriter। यह भी अगर आप चाहते हैं कि आप इसे संपीड़ित करने के लिए चुनने की अनुमति देता है और आपको फ़ाइल आकार पर अधिक नियंत्रण देता है। यदि आप जानते हैं कि यह 32767 से बड़ा नहीं होने जा रहा है short, intतो इसके बजाय सेव करें । एक बड़े लूप में, किसी चीज़ के shortबजाय किसी चीज़ को सहेजने का intमतलब बहुत छोटे फ़ाइल आकार से हो सकता है।

इसके अलावा, यदि आप इस मार्ग पर जाते हैं, तो मैं सुझाव देता हूं कि फ़ाइल में आपका पहला चर संस्करण संख्या हो।

उदाहरण के लिए विचार करें, एक मैप क्लास (बहुत सरलीकृत):

class Map {
    private const short MapVersion = 1;
    public string Name { get; set; }

    public void SaveMap(string filename) {
        //set up binary writer
        bw.Write(MapVersion);
        bw.Write(Name);
        //close/dispose binary writer
    }
    public void LoadMap(string filename) {
        //set up binary reader
        short mapVersion = br.ReadInt16();
        Name = br.ReadString();
        //close/dispose binary reader
    }
}

अब, मान लें कि आप अपने नक्शे में एक नई संपत्ति जोड़ना चाहते हैं, वस्तुओं Listका कहना है Platform। मैंने इसे उठाया क्योंकि यह थोड़ा अधिक शामिल है।

सबसे पहले, आप वेतन वृद्धि करते MapVersionहैं List:

private const short MapVersion = 2;
public string Name { get; set; }
public List<Platform> Platforms { get; set; }

फिर, सेव विधि अपडेट करें:

public void SaveMap(string filename) {
    //set up binary writer
    bw.Write(MapVersion);
    bw.Write(Name);
    //Save the count for loading later
    bw.Write(Platforms.Count);
    foreach(Platform plat in Platforms) {
        //For simplicities sake, I assume Platform has it's own
        // method to write itself to a file.
        plat.Write(bw);
    }
    //close/dispose binary writer
}

फिर, और यह वह जगह है जहाँ आप वास्तव में लाभ देखते हैं, लोड विधि को अपडेट करें:

public void LoadMap(string filename) {
    //set up binary reader
    short mapVersion = br.ReadInt16();
    Name = br.ReadString();
    //Create our platforms list
    Platforms = new List<Platform>();
    if (mapVersion >= 2) {
        //Version is OK, let's load the Platforms
        int mapCount = br.ReadInt32();
        for (int i = 0; i < mapCount; i++) {
            //Again, I'm going to assume platform has a static Read
            //  method that returns a Platform object
            Platforms.Add(Platform.Read(br));
        }
    } else {
        //If it's an older version, give it a default value
        Platforms.Add(new Platform());
    }
    //close/dispose binary reader
}

जैसा कि आप देख सकते हैं, LoadMapsविधि न केवल नक्शे के नवीनतम संस्करण को लोड कर सकती है, बल्कि पुराने संस्करण भी! जब यह पुराने मानचित्रों को लोड करता है, तो आपके द्वारा उपयोग किए जाने वाले डिफ़ॉल्ट मानों पर आपका नियंत्रण होता है।


9

लघु कथा

इस समस्या का एक वैकल्पिक विकल्प बिटमैप में अपने स्तर को स्टोर करना है, प्रति पिक्सेल एक पिक्सेल। RGBA का उपयोग करने से यह आसानी से एक ही छवि पर चार अलग-अलग आयामों (परतों, आईडी, रोटेशन, टिंट, आदि) को संग्रहीत करने की अनुमति देता है।

लम्बी कहानी

इस सवाल ने मुझे याद दिलाया कि जब नोच लिवस्ट्रीम ने कुछ महीने पहले अपनी लुदुम डेयर एंट्री की थी, और मैं यह जानना चाहूंगी कि अगर आपको पता नहीं है कि उसने क्या किया है। मुझे लगा कि यह वास्तव में दिलचस्प था।

मूल रूप से, उन्होंने अपने स्तर को संग्रहीत करने के लिए बिटमैप का उपयोग किया। बिटमैप में प्रत्येक पिक्सेल दुनिया में एक "टाइल" के अनुरूप होता है (वास्तव में उसके मामले में एक टाइल नहीं है क्योंकि यह एक पुनर्व्यवस्थित खेल था, लेकिन काफी करीब है)। उनके स्तरों में से एक का एक उदाहरण:

यहाँ छवि विवरण दर्ज करें

इसलिए यदि आप RGBA (8-बिट प्रति चैनल) का उपयोग करते हैं, तो आप प्रत्येक चैनल को एक अलग परत के रूप में उपयोग कर सकते हैं, और उनमें से प्रत्येक के लिए 256 प्रकार की टाइलें तक उपयोग कर सकते हैं। क्या यह पर्याप्त होगा? या उदाहरण के लिए, चैनलों में से एक टाइल के लिए रोटेशन को पकड़ सकता है जैसे आपने उल्लेख किया था। इसके अलावा, इस प्रारूप के साथ काम करने के लिए एक स्तर संपादक बनाना बहुत तुच्छ होना चाहिए।

और सबसे अच्छी बात यह है कि आपको किसी भी कस्टम कंटेंट प्रोसेसर की भी आवश्यकता नहीं है क्योंकि आप इसे किसी अन्य Texture2D की तरह XNA में लोड कर सकते हैं और पिक्सल को लूप में वापस पढ़ सकते हैं।

IIRC उसने दुश्मन पर संकेत देने के लिए मानचित्र पर एक शुद्ध लाल बिंदु का उपयोग किया, और उस पिक्सेल के लिए अल्फा चैनल के मूल्य के आधार पर यह दुश्मन के प्रकार को निर्धारित करेगा (उदाहरण के लिए 255 का अल्फा मान एक बल्ला हो सकता है जबकि 254 होगा) एक ज़ोंबी या कुछ और)।

एक और विचार आपके खेल की वस्तुओं को उन लोगों में वश में करना होगा जो एक ग्रिड में तय किए गए हैं, और जो टाइलों के बीच "बारीक" चल सकते हैं। बिटमैप में फिक्स्ड टाइल्स, और डायनामिक ऑब्जेक्ट को एक सूची में रखें।

यहां तक ​​कि उन 4 चैनलों में और अधिक जानकारी को मल्टीप्लेक्स करने का एक तरीका भी हो सकता है। अगर किसी को इस पर कोई विचार है, तो मुझे बताएं। :)


3

आप शायद लगभग किसी भी चीज़ से दूर हो सकते हैं। दुर्भाग्य से आधुनिक कंप्यूटर इतने तेज़ होते हैं कि यह अपेक्षाकृत कम मात्रा में डेटा वास्तव में ध्यान देने योग्य समय में अंतर नहीं करता है, भले ही यह एक फूला हुआ और बुरी तरह से निर्मित डेटा प्रारूप में संग्रहीत हो जो पढ़ने के लिए प्रसंस्करण की एक बड़ी मात्रा को तरसता है।

यदि आप "सही" बात करना चाहते हैं तो आप बाइनरी प्रारूप का सुझाव देते हैं जैसे कि Drackir ने सुझाव दिया है, लेकिन यदि आप किसी मूर्खतापूर्ण कारण के लिए कोई अन्य विकल्प बनाते हैं तो यह संभवत: वापस नहीं आएगा और आपको काट देगा (कम से कम प्रदर्शन बुद्धिमान नहीं)।


1
हाँ, यह निश्चित रूप से आकार पर निर्भर करता है। मेरे पास एक नक्शा है जो लगभग 161 000 टाइल है। जिनमें से प्रत्येक में 6 परतें हैं। मैं मूल रूप से XML में था, लेकिन यह 82MB था और लोड करने के लिए हमेशा के लिए ले गया । अब मैं इसे एक द्विआधारी प्रारूप में सहेजता हूं और यह संपीड़न से पहले 5mb है और लगभग 200ms में लोड होता है। :)
रिचर्ड मार्स्केल -

2

इस प्रश्न को देखें: गेम डेटा के लिए 'बाइनरी एक्सएमएल'? मैं JSON या YAML या यहां तक ​​कि XML का भी विकल्प चुनूंगा, लेकिन यह बहुत अधिक उपरि है। SQLite के लिए, मैं भंडारण के स्तर के लिए इसका इस्तेमाल कभी नहीं होगा। यदि आप संबंधित बहुत सारे डेटा को संग्रहीत करने की अपेक्षा करते हैं, तो एक रिलेशनल डेटाबेस आसान है (जैसे कि संबंधपरक लिंक / विदेशी कुंजी) और यदि आप बड़ी मात्रा में विभिन्न प्रश्न पूछने की अपेक्षा करते हैं, तो टीलमैप को संग्रहीत करना इस प्रकार का नहीं लगता है चीजें और अनावश्यक जटिलता जोड़ देगा।


2

इस प्रश्न के साथ मूलभूत समस्या यह है कि यह दो अवधारणाओं को स्वीकार करता है जिनका एक दूसरे से कोई लेना देना नहीं है:

  1. फ़ाइल संग्रहण प्रतिमान
  2. डेटा की इन-मेमोरी प्रतिनिधित्व

आप अपनी फ़ाइलों को सादे पाठ के रूप में कुछ मनमाना प्रारूप, JSON, Lua स्क्रिप्ट, XML, एक मनमाना द्विआधारी प्रारूप, आदि में संग्रहीत कर सकते हैं और इनमें से किसी की भी आवश्यकता नहीं होगी कि उस डेटा का आपकी इन-मेमोरी प्रतिनिधित्व किसी विशेष रूप में ले।

फ़ाइल संग्रहण प्रतिमान को आपके इन-मेमोरी प्रतिनिधित्व में परिवर्तित करना आपके लेवल लोडिंग कोड का काम है। उदाहरण के लिए, आप कहते हैं, "मैं टाइल डेटा को संग्रहीत करने के लिए डेटाबेस का उपयोग करके डेटा की कम अतिरेक को देखता हूं।" यदि आप कम अतिरेक चाहते हैं, तो यह आपके स्तर का लोडिंग कोड होना चाहिए। यह कुछ है जो आपके इन-मेमोरी प्रतिनिधित्व को संभालने में सक्षम होना चाहिए।

यह कुछ ऐसा नहीं है जिससे आपके फ़ाइल प्रारूप का संबंध होना चाहिए। और यहाँ क्यों है: उन फ़ाइलों को कहीं से आना होगा।

या तो आप इन्हें हाथ से लिखते जा रहे हैं, या आप किसी तरह के टूल का उपयोग करने जा रहे हैं जो डेटा को बनाता और संपादित करता है। यदि आप उन्हें हाथ से लिख रहे हैं, तो आपको जो सबसे महत्वपूर्ण चीज चाहिए वह है एक प्रारूप जो पढ़ना और संशोधित करना आसान है। डेटा अतिरेक कुछ ऐसा नहीं है जिसे आपके प्रारूप पर भी विचार करने की आवश्यकता है, क्योंकि आप अपना अधिकांश समय फाइलों को संपादित करने में लगाते हैं। क्या आप वास्तव में डेटा रिडंडेंसी प्रदान करने के लिए जो भी मैकेनिज्म चाहते हैं, उसका उपयोग स्वयं करना चाहते हैं? क्या यह आपके समय का बेहतर उपयोग नहीं होगा कि आपके लेवल लोडर ने इसे संभाल लिया है?

यदि आपके पास एक उपकरण है जो उन्हें बनाता है, तो पठनीयता के लिए वास्तविक प्रारूप केवल (सबसे अच्छा) मायने रखता है। आप इन फाइलों में कुछ भी डाल सकते हैं । यदि आप फ़ाइल में अनावश्यक डेटा को छोड़ना चाहते हैं, तो बस एक प्रारूप डिज़ाइन करें जो ऐसा कर सकता है, और अपने टूल को उस क्षमता का सही उपयोग कर सकता है। आपके tilemap प्रारूप में RLE (रन-लंबाई एन्कोडिंग) संपीड़न, दोहराव संपीड़न शामिल हो सकता है, जो कभी भी संपीड़न तकनीकें आप चाहते हैं, क्योंकि यह आपका tilemap प्रारूप है।

समस्या सुलझ गयी।

रिलेशनल डेटाबेस (RDB) डेटा के कई क्षेत्रों वाले बड़े डेटासेट पर जटिल खोजों को करने की समस्या को हल करने के लिए मौजूद हैं। टाइल मानचित्र में आप जिस प्रकार की खोज करते हैं वह एकमात्र "X, Y पर स्थिति प्राप्त करना" है। कोई भी एरे हैंडल कर सकता है। तिलमैप डेटा को स्टोर करने और बनाए रखने के लिए एक रिलेशनल डेटाबेस का उपयोग करना अत्यधिक ओवरकिल होगा, और वास्तव में कुछ भी लायक नहीं होगा।

यहां तक ​​कि अगर आप अपने इन-मेमोरी प्रतिनिधित्व में कुछ संपीड़न का निर्माण करते हैं, तो भी आप प्रदर्शन और मेमोरी पदचिह्न के संदर्भ में आरडीबी को आसानी से हरा पाएंगे। हां, आपको वास्तव में उस संपीड़न को लागू करना होगा। लेकिन अगर इन-मेमोरी डेटा का आकार एक ऐसी चिंता है जिसे आप आरडीबी मानेंगे, तो आप शायद वास्तव में विशिष्ट प्रकार के संपीड़न को लागू करना चाहते हैं। आप एक RDB से अधिक तेज़ होंगे और एक ही समय में मेमोरी में कम होंगे।


1
  • एक्सएमएल: वास्तव में उपयोग करने के लिए सरल है, लेकिन संरचना गहरा हो जाने पर ओवरहेड कष्टप्रद हो जाता है।
  • SQLite: बड़ी संरचनाओं के लिए अधिक सुविधाजनक है।

यदि आप पहले से ही XML लोडिंग और पार्सिंग से परिचित हैं, तो वास्तव में सरल डेटा के लिए, मैं शायद XML रूट पर जाऊंगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.