दो प्रमुख लाभ जो मैं लगातार सुनता हूँ, इकाई प्रणाली के बारे में प्रशंसा की जाती है 1) जटिल विरासत पदानुक्रम, और 2) कैश दक्षता के साथ उलझने के कारण नई प्रकार की संस्थाओं का आसान निर्माण नहीं है।
ध्यान दें कि (1) केवल ईएस / ईसीएस नहीं, बल्कि घटक-आधारित डिज़ाइन का एक लाभ है । आप कई तरीकों से घटकों का उपयोग कर सकते हैं जिनमें "सिस्टम" भाग नहीं है और वे बस ठीक काम करते हैं (और इंडी और एएए दोनों खेल ऐसे आर्किटेक्चर का उपयोग करते हैं)।
मानक यूनिटी ऑब्जेक्ट मॉडल (उपयोग GameObject
और MonoBehaviour
ऑब्जेक्ट) एक ईसीएस नहीं है, लेकिन घटक-आधारित डिज़ाइन है। नई एकता ईसीएस सुविधा बेशक एक वास्तविक ईसीएस है।
सिस्टम को एक से अधिक घटकों के साथ काम करने में सक्षम होने की आवश्यकता होती है, अर्थात, प्रतिपादन और भौतिकी प्रणाली दोनों को परिवर्तन घटक तक पहुंचने की आवश्यकता होती है।
कुछ ECS उनके घटक कंटेनरों को Entity ID द्वारा क्रमबद्ध करते हैं, जिसका अर्थ है कि प्रत्येक समूह में संबंधित घटक समान क्रम में होंगे।
इसका मतलब है कि यदि आप ग्राफिक्स घटक पर रेखीय रूप से पुनरावृत्ति कर रहे हैं तो आप इसी परिवर्तनशील घटकों पर रेखीय रूप से पुनरावृति कर रहे हैं । आप कुछ परिवर्तनों को छोड़ सकते हैं (क्योंकि आपके पास भौतिकी ट्रिगर वॉल्यूम हो सकते हैं जो आप प्रस्तुत नहीं करते हैं या ऐसे) लेकिन चूंकि आप हमेशा स्मृति में आगे जा रहे हैं (और विशेष रूप से बड़ी दूरी नहीं, आमतौर पर) आप अभी भी जा रहे हैं दक्षता हासिल करने के लिए।
यह एचपीसी के लिए अनुशंसित दृष्टिकोण होने के कारण आपके पास स्ट्रक्चर ऑफ एरेज़ (एसओए) के समान है। सीपीयू और कैश लगभग कई रैखिक सरणियों से निपट सकते हैं और साथ ही साथ यह एक एकल रैखिक सरणी के साथ सौदा कर सकते हैं, और यादृच्छिक मेमोरी एक्सेस से भी बेहतर हो सकते हैं।
कुछ ईसीएस कार्यान्वयनों में उपयोग की जाने वाली एक अन्य रणनीति - जिसमें यूनिटी ईसीएस भी शामिल है - उनके संबंधित इकाई के आर्कटेप के आधार पर घटकों को आवंटित करना है। है यही कारण है, ठीक अवयव के सेट के साथ सभी संस्थाओं ( PhysicsBody
, Transform
) अलग अलग घटकों के साथ संस्थाओं से आवंटित किया जाएगा (जैसे PhysicsBody
, Transform
, और Renderable
)।
इस तरह के डिजाइन में सिस्टम सबसे पहले सभी आर्कटाइप्स को खोजने के लिए काम करते हैं जो उनकी आवश्यकताओं से मेल खाते हैं (जिनके पास अवयवों का आवश्यक सेट है), जो कि आर्कटेप्स की सूची की पुनरावृत्ति करता है, और प्रत्येक मिलान आर्केचे के भीतर संग्रहीत घटकों को पुनरावृत्त करता है। यह पूरी तरह से रैखिक और सच्चे O (1) घटक को एक आर्कहिट के भीतर उपयोग करने की अनुमति देता है और सिस्टम को बहुत कम ओवरहेड के साथ संगत एंटिटीज़ खोजने की अनुमति देता है (संभावित सैकड़ों सैकड़ों एंटिटीज़ को खोजने के बजाय आर्कटेप्स की एक छोटी सूची की खोज करके)।
आपके पास अन्य घटकों के लिए पॉइंटर्स स्टोर हो सकते हैं, या पॉइंटर्स को स्टोर करने वाली संस्थाओं के लिए पॉइंटर्स हो सकते हैं।
एक ही इकाई पर अन्य घटकों को संदर्भित करने वाले घटकों को कुछ भी संग्रहीत करने की आवश्यकता नहीं है। अन्य संस्थाओं पर घटकों को संदर्भित करने के लिए, बस इकाई आईडी को स्टोर करें।
यदि किसी एकल इकाई के लिए एक घटक को एक से अधिक बार अस्तित्व में रखने की अनुमति है और आपको किसी विशेष उदाहरण को संदर्भित करने की आवश्यकता है, तो उस इकाई के लिए अन्य इकाई की आईडी और एक घटक सूचकांक को संग्रहीत करें। कई ईसीएस कार्यान्वयन इस मामले की अनुमति नहीं देते हैं, हालांकि, विशेष रूप से क्योंकि यह इन कार्यों को कम कुशल बनाता है।
आप यह सुनिश्चित कर सकते हैं कि प्रत्येक घटक सरणी 'n' बड़ी है, जहाँ 'n' सिस्टम में जीवित संस्थाओं की संख्या है
हैंडल का उपयोग करें (जैसे सूचक + पीढ़ी मार्कर) और संकेत नहीं और फिर आप ऑब्जेक्ट संदर्भों को तोड़ने के डर के बिना सरणियों का आकार बदल सकते हैं।
std::deque
यदि आप किसी कारण के लिए संकेत देना चाहते हैं या यदि आपने कोई समस्या मापी है, तो आप कई सामान्य कार्यान्वयन के समान ("एरे की एक सरणी)" का भी उपयोग कर सकते हैं (हालाँकि उक्त क्रियान्वयन के दयनीय-छोटे छोटे आकार के बिना)। सरणी आकार प्रदर्शन।
दूसरे, यह सभी मान रहे हैं कि संस्थाओं को हर फ्रेम / टिक की सूची में रैखिक रूप से संसाधित किया जाता है, लेकिन वास्तव में ऐसा अक्सर नहीं होता है
यह इकाई पर निर्भर करता है। हां, कई उपयोग मामलों के लिए, यह सच नहीं है। वास्तव में, यही कारण है कि मैं घटक-आधारित डिजाइन (अच्छा) और इकाई-प्रणाली (सीबीडी का एक विशिष्ट रूप ) के बीच के अंतर पर बहुत जोर देता हूं ।
आपके कुछ घटकों को निश्चित रूप से रैखिक रूप से संसाधित करना आसान होगा। यहां तक कि आम तौर पर "ट्री हैवी" उपयोग के मामलों में हमने निश्चित रूप से देखा है कि कसकर पैक किए गए सरणियों का उपयोग करने से प्रदर्शन बढ़ता है (ज्यादातर मामलों में कुछ एक एन के सबसे अधिक, एक सामान्य गेम में एआई एजेंट की तरह)।
कुछ डेवलपर्स ने यह भी पाया है कि डेटा-उन्मुख रैखिक-आवंटित डेटा संरचनाओं का उपयोग करने के प्रदर्शन लाभ "स्मार्ट" ट्री-आधारित संरचनाओं का उपयोग करने के प्रदर्शन लाभ को पछाड़ते हैं। यह सब खेल और विशिष्ट उपयोग के मामलों पर निर्भर करता है।
मान लें कि आप एक क्षेत्र / पोर्टल रेंडरर या ऑक्ट्री का उपयोग रोड़ा बनाने के लिए करते हैं। आप एक सेक्टर / नोड के भीतर संस्थाओं को स्टोर करने में सक्षम हो सकते हैं, लेकिन आप इसे पसंद करने वाले हैं या नहीं।
आपको आश्चर्य होगा कि सरणी अभी भी कितनी मदद करती है। आप "कहीं भी" की तुलना में स्मृति के बहुत छोटे क्षेत्र में चारों ओर कूद रहे हैं और यहां तक कि सभी कूदने से आप अभी भी कैश में किसी चीज़ को समाप्त करने की अधिक संभावना रखते हैं। एक निश्चित आकार या उससे कम के पेड़ के साथ, आप पूरी चीज़ को कैश में प्रीफ़ैच करने में सक्षम हो सकते हैं और उस पेड़ पर कभी भी कैश की कमी नहीं होती है।
पेड़ की संरचनाएं भी हैं जो कसकर पैक किए गए सरणियों में रहने के लिए बनाई गई हैं। उदाहरण के लिए, अपने ऑक्ट्री के साथ, आप एक ढेर जैसी संरचना का उपयोग कर सकते हैं (बच्चों से पहले माता-पिता, एक-दूसरे के बगल में भाई-बहन) और यह सुनिश्चित करें कि जब भी आप उस पेड़ को "ड्रिल" करते हैं तो आप हमेशा सरणी में आगे की ओर बढ़ते हैं, जो मदद करता है CPU मेमोरी एक्सेस / कैश लुक्स को ऑप्टिमाइज़ करता है।
जो बनाने के लिए एक महत्वपूर्ण बिंदु है। एक x86 CPU एक जटिल जानवर है। सीपीयू आपके मशीन कोड पर प्रभावी रूप से एक माइक्रोकोड ऑप्टिमाइज़र चला रहा है, इसे छोटे माइक्रोकोड में बदल रहा है और निर्देशों को पुन: व्यवस्थित कर रहा है, मेमोरी एक्सेस पैटर्न की भविष्यवाणी कर रहा है, डेटा एक्सेस पैटर्न से अधिक आसानी से स्पष्ट हो सकता है यदि आपके पास सभी उच्च स्तर की समझ है सीपीयू या कैश कैसे काम करता है।
फिर आपके पास अन्य सिस्टम हैं, जो किसी अन्य क्रम में संग्रहीत संस्थाओं को पसंद कर सकते हैं।
आप उन्हें कई बार स्टोर कर सकते हैं। एक बार जब आप अपने सरणियों को नंगे न्यूनतम विवरणों पर ले जाते हैं, तो हो सकता है कि आप इस दृष्टिकोण के साथ वास्तव में मेमोरी को बचा सकें (क्योंकि आपने अपने 64-बिट पॉइंटर्स को हटा दिया है और छोटे सूचकांकों का उपयोग कर सकते हैं)।
आप अलग-अलग सरणियों को रखने के बजाय अपनी इकाई सरणी को इंटरलेव कर सकते हैं, लेकिन आप अभी भी मेमोरी बर्बाद कर रहे हैं
यह अच्छा कैश उपयोग के लिए विरोधी है। यदि आप सभी के बारे में ध्यान रखते हैं कि ट्रांसफ़ॉर्म और ग्राफिक्स डेटा हैं, तो मशीन भौतिक विज्ञान और एआई और इनपुट और डीबग वगैरह के लिए अन्य सभी डेटा खींचने में समय क्यों लगाती है?
यह आमतौर पर ईसीएस बनाम अखंड गेम ऑब्जेक्ट्स के पक्ष में बनाया गया बिंदु है (हालांकि अन्य घटक-आधारित आर्किटेक्चर की तुलना में वास्तव में लागू नहीं होता है)।
इसके लायक क्या है, सबसे अधिक "प्रोडक्शन-ग्रेड" ईसीएस कार्यान्वयन है जिसके बारे में मुझे पता है कि इंटरलेयर्ड स्टोरेज का उपयोग किया जाता है। मेरे द्वारा पहले उल्लेख किए गए लोकप्रिय आर्कटाइप दृष्टिकोण (उदाहरण के लिए, यूनिटी ईसीएस में प्रयुक्त), एक आर्कएप्टाइप से जुड़े घटकों के लिए इंटरलेयर्ड स्टोरेज का उपयोग करने के लिए स्पष्ट रूप से निर्मित है।
AI व्यर्थ है यदि यह किसी इकाई के प्रतिपादन के लिए उपयोग किए जाने वाले परिवर्तन या एनीमेशन स्थिति को प्रभावित नहीं कर सकता है।
सिर्फ इसलिए कि AI कुशलता से रूपांतरित डेटा का उपयोग नहीं कर सकता है इसका मतलब यह नहीं है कि कोई अन्य सिस्टम उस डेटा लेआउट अनुकूलन का प्रभावी ढंग से उपयोग नहीं कर सकता है। आप गेम लॉजिक सिस्टम को बिना रोक-टोक डेटा को ट्रांसफॉर्म करने के लिए पैक्ड ऐरे का इस्तेमाल कर सकते हैं।
आप कोड कैश को भी भूल रहे हैं । जब आप ECS के सिस्टम दृष्टिकोण का उपयोग करते हैं (कुछ अधिक भोले घटक आर्किटेक्चर के विपरीत) तो आप गारंटी दे रहे हैं कि आप कोड के एक ही छोटे लूप को चला रहे हैं और वर्चुअल फ़ंक्शन तालिकाओं के माध्यम से आगे-पीछे नहीं कूदते हुए यादृच्छिक Update
कार्यों के वर्गीकरण तक पहुंच गए हैं आपका बाइनरी। इसलिए एआई मामले में, आप वास्तव में अपने सभी अलग-अलग एआई घटकों को रखना चाहते हैं (क्योंकि निश्चित रूप से आपके पास एक से अधिक है ताकि आप व्यवहारों की रचना कर सकें!) अलग-अलग बाल्टियों में और प्रत्येक सूची को अलग से संसाधित करने के लिए सबसे अच्छा कोड कैश उपयोग प्राप्त करें।
विलंबित ईवेंट कतार के साथ (जहां एक सिस्टम ईवेंट की एक सूची बनाता है, लेकिन उन्हें तब तक नहीं भेजता है जब तक कि सिस्टम सभी संस्थाओं को संसाधित करना समाप्त नहीं करता है) आप यह सुनिश्चित कर सकते हैं कि ईवेंट्स को रखने के दौरान आपके कोड कैश का अच्छी तरह से उपयोग किया जाता है।
एक दृष्टिकोण का उपयोग करना जहां प्रत्येक प्रणाली को पता है कि फ्रेम के लिए बाहर पढ़ने के लिए कौन सी घटना की कतार है, आप यहां तक कि पढ़ने की घटनाओं को तेज कर सकते हैं । या बिना तेजी से, कम से कम।
याद रखें, प्रदर्शन निरपेक्ष नहीं है। अच्छे डेटा-उन्मुख डिज़ाइन के प्रदर्शन लाभों को देखने के लिए आपको हर अंतिम एकल कैश मिस को समाप्त करने की आवश्यकता नहीं है।
ईसीएस आर्किटेक्चर और डेटा-उन्मुख डिज़ाइन पैटर्न के साथ कई गेम सिस्टम को बेहतर बनाने में अभी भी सक्रिय शोध है। इसी तरह हाल के वर्षों में हमने SIMD के साथ जो कुछ अद्भुत चीजें देखीं (जैसे JSON पार्सर्स), हम अधिक से अधिक चीजों को ECS आर्किटेक्चर के साथ देख रहे हैं, जो कि शास्त्रीय गेम आर्किटेक्चर के लिए सहज नहीं लगता है लेकिन कई नंबर प्रदान करता है लाभ (गति, बहु सूत्रण, परीक्षणशीलता, आदि)।
या शायद एक हाइब्रिड दृष्टिकोण है जो हर किसी का उपयोग कर रहा है लेकिन किसी के बारे में बात नहीं कर रहा है
यह वह है जो मैंने अतीत में वकालत की है, खासकर उन लोगों के लिए जो ईसीएस आर्किटेक्चर से उलझन में हैं: उन घटकों के लिए अच्छे डेटा-उन्मुख दृष्टिकोण का उपयोग करें जहां प्रदर्शन महत्वपूर्ण है। सरल वास्तुकला का उपयोग करें जहां सादगी विकास के समय को बेहतर बनाती है। ECS प्रपोजल की तरह हर एक कंपोनेंट को एक सख्त ओवर-डेफिनिशन में शू-हॉर्न न करें। अपने कंपोनेंट आर्किटेक्चर को इस तरह से विकसित करें कि आप आसानी से ईसीएस जैसे दृष्टिकोण का उपयोग कर सकें, जहां वे समझ में आते हैं और सरल घटक संरचना का उपयोग करते हैं जहां ईसीएस जैसा दृष्टिकोण समझ में नहीं आता (या पेड़ की संरचना की तुलना में कम समझ में आता है, या इसी तरह) ।
मैं व्यक्तिगत रूप से ईसीएस की वास्तविक शक्ति में खुद को अपेक्षाकृत हाल ही में परिवर्तित कर रहा हूं। हालांकि मेरे लिए, निर्णायक कारक कुछ ऐसा था जो ईसीएस के बारे में शायद ही कभी उल्लेख किया गया था: यह गेम सिस्टम और तर्क के लिए लेखन परीक्षण करता है जो मैंने पिछले दिनों के साथ काम किया है, कसकर युग्मित तर्क-युक्त घटक-आधारित डिज़ाइनों की तुलना में लगभग तुच्छ है। चूंकि ईसीएस आर्किटेक्चर ने सिस्टम में सभी तर्क दिए हैं, जो केवल घटकों का उपभोग करते हैं और घटक अपडेट का उत्पादन करते हैं, सिस्टम व्यवहार का परीक्षण करने के लिए घटकों का "नकली" सेट बनाना काफी आसान है; क्योंकि अधिकांश गेम लॉजिक को पूरी तरह से सिस्टम के अंदर रहना चाहिए, इसका प्रभावी अर्थ यह है कि आपके सभी सिस्टम का परीक्षण आपके गेम लॉजिक के काफी उच्च कोड कवरेज प्रदान करेगा। सिस्टम आपकी तुलना में कम जटिलता या प्रदर्शन प्रभाव वाले परीक्षणों के लिए नकली निर्भरता (जैसे GPU इंटरफेस) का उपयोग कर सकते हैं '
एक तरफ के रूप में, आप ध्यान दें कि बहुत से लोग ईसीएस के बारे में बात कर सकते हैं बिना वास्तव में समझे कि यह क्या है। मुझे लगता है कि क्लासिक यूनिटी को ईसीएस के रूप में संदर्भित किया गया है जो निराशाजनक आवृत्ति के साथ है, यह दर्शाता है कि बहुत सारे गेम डेवलपर "ईसीएस" को "अवयव" के साथ समान करते हैं और बहुत "एंटिटी सिस्टम" भाग को पूरी तरह से अनदेखा करते हैं। आप इंटरनेट पर ईसीएस पर ढेर सारा प्यार देखते हैं जब लोगों का एक बड़ा हिस्सा वास्तव में केवल घटक-आधारित डिज़ाइन की वकालत करता है, वास्तविक ईसीएस नहीं। इस बिंदु पर यह बहस करने के लिए लगभग व्यर्थ है; ईसीएस एक सामान्य शब्द में अपने मूल अर्थ से दूषित हो गया है और आप यह भी स्वीकार कर सकते हैं कि "ईसीएस" का अर्थ "डेटा-उन्मुख ईसीएस" के समान नहीं है। : /