एक ही घटक की समूहों को रैखिक स्मृति में सेट करना


12

हम बुनियादी प्रणालियों-घटकों-संस्थाओं के दृष्टिकोण से शुरू करते हैं ।

आइए संयोजन बनाते हैं ( इस लेख से व्युत्पन्न शब्द ) केवल घटकों के प्रकार के बारे में जानकारी से बाहर । यह गतिशील रूप से रनटाइम पर किया जाता है, जैसे हम एक इकाई में एक-एक करके घटकों को जोड़ेंगे / हटाएंगे, लेकिन चलो इसे अधिक सटीक नाम दें क्योंकि यह केवल टाइप जानकारी के बारे में है।

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

अब मुख्य अवधारणा के लिए: जब भी कोई इकाई बनाई जाती है, तो उसे असेंबलिंग बकेट नामक एक वस्तु को सौंपा जाता है , जिसका अर्थ है कि एक ही हस्ताक्षर की सभी इकाइयाँ एक ही कंटेनर (जैसे std :: वेक्टर) में होंगी।

अब प्रणालियाँ अपनी रुचि के हर बकेट के माध्यम से पुनरावृति करती हैं और अपना काम करती हैं।

इस दृष्टिकोण के कुछ फायदे हैं:

  • घटकों को कुछ में संग्रहित किया जाता है (ठीक-ठीक: बाल्टियों की संख्या) सन्निहित मेमोरी चंक्स - इससे मेमोरी मित्रता में सुधार होता है और किसी भी गेम स्टेट को डंप करना आसान होता है
  • सिस्टम एक रैखिक तरीके से घटकों को संसाधित करते हैं, जिसका अर्थ है कि कैश सुसंगतता में सुधार - अलविदा शब्दकोष और यादृच्छिक मेमोरी जंप
  • एक नई इकाई बनाना उतना ही आसान है जितना कि एक असेंबलिंग को बाल्टी में मैप करना और इसके वेक्टर में आवश्यक घटकों को पीछे धकेलना
  • एक इकाई को हटाना std के लिए एक कॉल के रूप में आसान है :: हटाए गए के साथ अंतिम तत्व को स्वैप करने के लिए कदम, क्योंकि इस समय आदेश नहीं देता है

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

यदि हमारे पास पूरी तरह से अलग-अलग हस्ताक्षरों के साथ बहुत सारी संस्थाएं हैं, तो कैश कोशिनी के प्रकार का लाभ कम हो जाता है, लेकिन मुझे नहीं लगता कि यह अधिकांश अनुप्रयोगों में होगा।

एक बार वैक्टर के पुन: व्यवस्थित होने पर पॉइंटर अमान्य होने की समस्या भी होती है - इसे एक संरचना की तरह पेश करके हल किया जा सकता है:

struct assemblage_bucket {
    struct entity_watcher {
        assemblage_bucket* owner;
        entity_id real_index_in_vector;
    };

    std::unordered_map<entity_id, std::vector<entity_watcher*>> subscribers;

    //...
};

इसलिए जब भी हमारे गेम लॉजिक में किसी कारण से हम एक नई बनाई गई इकाई पर नज़र रखना चाहते हैं, तो बाल्टी के अंदर हम एक Unit_watcher रजिस्टर करते हैं , और एक बार इकाई को std होने के बाद :: हटाने के दौरान स्थानांतरित किया जाता है, हम इसके वॉचर्स को अपडेट करते हैं और अपडेट करते हैं उनके real_index_in_vectorनए मूल्यों के लिए। अधिकांश समय यह प्रत्येक निकाय विलोपन के लिए केवल एक शब्दकोष लुकअप लगाता है।

क्या इस दृष्टिकोण के लिए कोई और नुकसान हैं?

बहुत स्पष्ट होने के बावजूद समाधान का उल्लेख क्यों नहीं किया गया है?

संपादित करें : मैं सवालों के जवाब देने के लिए सवाल का संपादन कर रहा हूं, क्योंकि टिप्पणियां अपर्याप्त हैं।

आप प्लग करने योग्य घटकों की गतिशील प्रकृति को खो देते हैं, जो विशेष रूप से स्थिर वर्ग निर्माण से दूर करने के लिए बनाया गया था।

मैं नही। शायद मैंने इसे स्पष्ट रूप से पर्याप्त नहीं बताया:

auto signature = world.get_signature(entity_id); // this would just return entity_id.bucket_owner->bucket_signature or so
signature.add(foo_component);
signature.remove(bar_component);
world.delete_entity(entity_id); // entity_id would hold information about its bucket owner
world.create_entity(signature); // automatically assigns new entity to an existing or a new bucket

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

आपको सभी बाल्टियों से गुजरना होगा जिसमें एक वैध लक्ष्य हो सकता है। बाहरी डेटा संरचना के बिना, टकराव का पता लगाना उतना ही मुश्किल हो सकता है।

खैर, यही कारण है कि हमारे पास बाह्य डेटा संरचनाएं हैं । वर्कअराउंड सिस्टम क्लास में एक पुनरावृत्ति शुरू करने के रूप में सरल है जो अगले बकेट में कूदने के लिए पता लगाता है। कूद विशुद्ध रूप से तर्क के लिए पारदर्शी होगा।


मैंने वैक्टर में सभी घटकों को संग्रहीत करने के बारे में रैंडी गॉल लेख भी पढ़ा और उनके सिस्टम को बस उन्हें संसाधित करने दिया। मुझे वहां दो बड़ी समस्याएं दिखाई देती हैं: क्या होगा यदि मैं केवल एक उप-सेट को अपडेट करना चाहता हूं (उदाहरण के लिए पुलिंग के बारे में सोचें)। क्योंकि घटकों को संस्थाओं के साथ फिर से जोड़ा जाएगा। प्रत्येक घटक पुनरावृत्ति कदम के लिए मुझे यह जाँचने की आवश्यकता होगी कि क्या वह इकाई जो किसी अद्यतन के लिए चुनी गई है। दूसरी समस्या यह है कि कुछ प्रणालियों को फिर से कैश की सहानुभूति का लाभ लेते हुए कई अलग-अलग घटकों को संसाधित करने की आवश्यकता होती है। कोई भी विचार इन मुद्दों से कैसे निपटें?
टिगुची

जवाबों:


7

आपने अनिवार्य रूप से एक पूल आवंटनकर्ता के साथ और गतिशील कक्षाओं के साथ एक स्थिर ऑब्जेक्ट सिस्टम तैयार किया है।

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

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

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


मैंने कहा: हम इकाई के हस्ताक्षर को नहीं बदल सकते हैं, और मेरा मतलब है कि हम इसे सीधे-सीधे संशोधित नहीं कर सकते हैं, लेकिन फिर भी हम केवल एक स्थानीय प्रतिलिपि को मौजूदा असेंबल प्राप्त कर सकते हैं, इसमें बदलाव कर सकते हैं और एक नई इकाई के रूप में फिर से अपलोड कर सकते हैं - और ये ऑपरेशन काफी सस्ते हैं, जैसा कि मैंने प्रश्न में दिखाया है। एक बार फिर - केवल एक "बाल्टी" वर्ग है। "असेम्बलेज" / "सिग्नेचर" / "आइए इसे नाम दें लेकिन हम चाहते हैं कि इसे एक मानक दृष्टिकोण के रूप में रनटाइम पर गतिशील रूप से बनाया जा सके", मैं यहां तक ​​कि एक इकाई को "हस्ताक्षर" के रूप में सोच रहा हूं।
पेट्रीक कज़ाचर्सकी

और मैंने कहा कि आप जरूरी नहीं चाहते हैं कि हम इससे निपटें। "नई इकाई बनाना" का अर्थ संभावित रूप से इकाई के सभी मौजूदा हैंडल को तोड़ना हो सकता है, यह इस बात पर निर्भर करता है कि आपका हैंडल सिस्टम कैसे काम करता है। आपका फोन अगर वे काफी सस्ते हैं या नहीं। मैंने पाया कि इससे निपटने के लिए बट में दर्द होना चाहिए।
सीन मिडिलिचच

ठीक है, अब मुझे इस बारे में अपनी बात मिल गई है। वैसे भी मुझे लगता है कि अगर जोड़ना / हटाना थोड़ा अधिक महंगा था, तो यह बहुत ही महत्वपूर्ण है कि यह अभी भी घटकों को एक्सेस करने की प्रक्रिया को बहुत सरल बनाने के लायक है, जो वास्तविक समय में होता है। तो, "बदलते" का ओवरहेड लापरवाही है। अपने AI उदाहरण के बारे में, क्या यह अभी भी इन कुछ प्रणालियों के लायक नहीं है जो कि कई घटकों के डेटा की आवश्यकता है?
पैट्रीक कज़ाचर्सकी

मेरा कहना यह था कि एआई एक ऐसी जगह थी जहां आपका दृष्टिकोण बेहतर है, लेकिन अन्य घटकों के लिए ऐसा जरूरी नहीं है।
शॉन मिडिलडविच

4

आपने जो किया है वह C ++ ऑब्जेक्ट्स को री-इंजीनियर किया है। यह स्पष्ट होने का कारण यह है कि यदि आप "इकाई" शब्द की जगह "वर्ग" और "घटक" को "सदस्य" से बदलते हैं तो यह मिश्रणों का उपयोग करते हुए एक मानक ओओपी डिज़ाइन है।

1) आप प्लग करने योग्य घटकों की गतिशील प्रकृति को खो देते हैं, जो विशेष रूप से स्थिर वर्ग निर्माण से दूर होने के लिए बनाया गया था।

2) मेमोरी सुसंगतता एक डेटा प्रकार के भीतर सबसे महत्वपूर्ण है, न कि किसी वस्तु के भीतर एक स्थान पर कई डेटा प्रकारों को एकीकृत करने के लिए। यह एक कारण है कि घटक + सिस्टम बनाए गए थे, क्लास + ऑब्जेक्ट मेमोरी टुकड़े से दूर होने के लिए।

3) यह डिज़ाइन C ++ वर्ग शैली के लिए भी सम्मान करता है क्योंकि आप इकाई को एक सुसंगत वस्तु के रूप में सोच रहे हैं, जब एक घटक + सिस्टम डिज़ाइन में, इकाई मनुष्यों के लिए आंतरिक कामकाज को समझने के लिए केवल एक टैग / आईडी है।

4) यह एक घटक के लिए खुद को एक जटिल वस्तु की तुलना में खुद को क्रमबद्ध करने के लिए आसान है, अगर अपने आप में एक प्रोग्रामर के रूप में ट्रैक रखना आसान नहीं है।

5) इस रास्ते के नीचे अगला तार्किक कदम सिस्टम को हटाने और उस कोड को सीधे इकाई में डालना है, जहां यह सभी डेटा है जिसे इसे काम करने की आवश्यकता है। हम सभी देख सकते हैं कि इसका क्या अर्थ है =)


2) शायद मैं कैशिंग को पूरी तरह से नहीं समझता, लेकिन मान लीजिए कि एक सिस्टम है जो 10 घटकों के साथ काम करता है। एक मानक दृष्टिकोण में, प्रत्येक इकाई को संसाधित करने का अर्थ है 10 बार रैम तक पहुंचना, क्योंकि घटक मेमोरी में यादृच्छिक स्थानों पर बिखरे हुए हैं, भले ही पूल का उपयोग किया जाए - क्योंकि विभिन्न घटक अलग-अलग पूल से संबंधित हैं। क्या एक बार में पूरी इकाई को कैश करना और एक ही कैश मिस के बिना सभी घटकों को प्रोसेस करना, शब्दकोश लुकअप के बिना भी महत्वपूर्ण नहीं होगा? इसके अलावा, मैंने 1) बिंदु को कवर करने के लिए एक संपादन किया
पैट्रीक कज़ाचर्सकी

@ सीन मिडल्डिच ने अपने जवाब में इस कैचिंग ब्रेकडाउन का अच्छा वर्णन किया है।
पैट्रिक ह्यूजेस

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

5) और मुझे नहीं लगता कि इस विचार में कुछ भी इस दिशा की ओर इशारा करता है। ऐसा नहीं है कि मैं आपसे सहमत नहीं होना चाहता, मैं बस उत्सुक हूं कि यह चर्चा कहां तक ​​पहुंच सकती है, हालांकि वैसे भी शायद यह "इसे मापने" या प्रसिद्ध "समयपूर्व अनुकूलन" की तरह होगा। :)
पैट्रिक कज़ाचर्सकी

@PatrykCzachurski लेकिन आपके सिस्टम 10 घटकों के साथ काम नहीं करते हैं।
user253751

3

संस्थाओं को एक साथ रखना उतना महत्वपूर्ण नहीं है जितना कि आप सोच सकते हैं, यही कारण है कि "क्योंकि यह एक इकाई है" के अलावा अन्य किसी वैध कारण के बारे में सोचना मुश्किल है। लेकिन जब से आप वास्तव में कैश सुसंगतता के लिए तार्किक सुसंगतता के विपरीत कर रहे हैं, यह समझ में आ सकता है।

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

तार्किक सुसंगतता के लिए संस्थाओं को एक साथ व्यवस्थित करने के बारे में जारी रखने के लिए, मुझे अपने मिशन में पहचान के उद्देश्यों के लिए संस्थाओं को एक साथ रखना पड़ सकता है। मुझे यह जानने की जरूरत है कि क्या आपने केवल इकाई प्रकार ए या टाइप बी बनाया है, और मैं इसके द्वारा प्राप्त करता हूं ... आपने यह अनुमान लगाया: एक नया घटक जोड़ना जो इस इकाई को एक साथ रखने वाले संयोजन को पहचानता है। फिर भी, मैं एक भव्य कार्य के लिए सभी घटकों को एक साथ इकट्ठा नहीं कर रहा हूं, मुझे बस यह जानना होगा कि यह क्या है। इसलिए मुझे नहीं लगता कि यह हिस्सा बहुत उपयोगी है।


मुझे स्वीकार करना होगा कि मैं आपके उत्तर को काफी नहीं समझता। "तार्किक सुसंगतता" से आपका क्या अभिप्राय है? बातचीत में कठिनाइयों के बारे में, मैंने एक संपादन किया।
पेट्रीक कज़ाचर्सकी

"तार्किक सामंजस्य", जैसा कि: यह एक पेड़ इकाई को एक साथ बनाने वाले सभी घटकों को रखने के लिए "तार्किक अर्थ" बनाता है।
जॉन मैकडॉनल्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.