मैं एक छोटे से अनुभव से बात करने जा रहा हूं, एक कठोर OO- डिजाइन से एक इकाई-घटक-प्रणाली (ECS) डिजाइन पर जा रहा हूं।
कुछ समय पहले मैं भी आपकी तरह ही था , मेरे पास विभिन्न प्रकार की चीजों का एक समूह था जिसमें समान गुण थे और मैंने विभिन्न वस्तुओं का निर्माण किया और इसे हल करने के लिए विरासत का उपयोग करने की कोशिश की। एक बहुत होशियार व्यक्ति ने मुझसे कहा कि मैं ऐसा नहीं करता, और इसके बजाय, इकाई-घटक-प्रणाली का उपयोग करें।
अब, ईसीएस एक बड़ी अवधारणा है, और सही होने के लिए यह कठिन है। इसमें बहुत सारे काम हैं जो इसमें जाते हैं, ठीक से संस्थाओं, घटकों और प्रणालियों का निर्माण करते हैं। इससे पहले कि हम ऐसा कर सकें, हालांकि, हमें शर्तों को परिभाषित करने की आवश्यकता है।
- इकाई : यह चीज है , खिलाड़ी, पशु, एनपीसी, जो भी हो । यह एक ऐसी चीज है जिसे इसके साथ जुड़े घटकों की आवश्यकता होती है।
- घटक : यह विशेषता या संपत्ति है , जैसे "नाम" या "आयु", या "माता-पिता", आपके मामले में।
- सिस्टम : यह एक घटक, या एक व्यवहार के पीछे का तर्क है । आमतौर पर, आप प्रति घटक एक सिस्टम बनाते हैं, लेकिन यह हमेशा संभव नहीं होता है। इसके अतिरिक्त, कभी-कभी सिस्टम को अन्य प्रणालियों को प्रभावित करने की आवश्यकता होती है ।
तो, यहाँ मैं इस के साथ जाना होगा:
सबसे पहले और सबसे महत्वपूर्ण, ID
अपने पात्रों के लिए बनाएं । एक int
, Guid
जो भी आपको पसंद है। यह "इकाई" है।
दूसरा, आपके द्वारा किए जा रहे विभिन्न व्यवहारों के बारे में सोचना शुरू करें। "फैमिली ट्री" जैसी चीजें - यह एक व्यवहार है। मॉडलिंग के बजाय इकाई पर विशेषता के रूप में, एक ऐसी प्रणाली का निर्माण करें जो सभी जानकारी रखती है । सिस्टम तब तय कर सकता है कि इसके साथ क्या करना है।
इसी तरह, हम "चरित्र जीवित है या मृत?" यह आपके डिजाइन में सबसे महत्वपूर्ण प्रणालियों में से एक है, क्योंकि यह अन्य सभी को प्रभावित करता है। कुछ सिस्टम "मृत" अक्षर (जैसे "स्प्राइट" सिस्टम) को हटा सकते हैं, अन्य सिस्टम आंतरिक रूप से नई स्थिति का बेहतर समर्थन करने के लिए चीजों को फिर से व्यवस्थित कर सकते हैं।
आप एक "स्प्राइट" या "ड्राइंग" या "रेंडरिंग" प्रणाली का निर्माण करेंगे, उदाहरण के लिए। इस प्रणाली में यह निर्धारित करने की जिम्मेदारी होगी कि चरित्र को किस अंक के साथ प्रदर्शित किया जाना चाहिए और इसे कैसे प्रदर्शित किया जाए। फिर, जब कोई पात्र मर जाता है, तो उन्हें हटा दें।
इसके अतिरिक्त, एक "एआई" प्रणाली जो एक चरित्र को बता सकती है कि क्या करना है, कहां जाना है, आदि। यह कई अन्य प्रणालियों के साथ बातचीत करना चाहिए, और उनके आधार पर निर्णय लेना चाहिए। फिर से, मृत पात्रों को संभवतः इस प्रणाली से हटाया जा सकता है, क्योंकि वे वास्तव में अब और कुछ नहीं कर रहे हैं।
आपके "नाम" प्रणाली और "परिवार के पेड़" प्रणाली को संभवतः चरित्र (जीवित या मृत) को स्मृति में रखना चाहिए। इस प्रणाली को उस जानकारी को याद करने की आवश्यकता है, चाहे चरित्र की स्थिति क्या हो। (जिम अभी भी जिम है, हम उसे दफनाने के बाद भी।)
यह तब भी आपको बदलने का लाभ देता है जब एक सिस्टम अधिक कुशलता से प्रतिक्रिया करता है : सिस्टम का अपना टाइमर होता है। कुछ प्रणालियों को तेजी से आग लगाने की जरूरत है, कुछ नहीं। यह वह जगह है जहां हम एक खेल को कुशलता से चलाने के लिए शुरू करते हैं। हमें हर मिलीसेकंड के मौसम की पुन: गणना करने की आवश्यकता नहीं है, हम शायद ऐसा हर 5 या उसके बाद कर सकते हैं।
यह आपको अधिक रचनात्मक उत्तोलन भी देता है: आप एक "पाथफाइंडर" प्रणाली का निर्माण कर सकते हैं जो ए-टू-बी से एक पथ की गणना को संभाल सकती है, और आवश्यकतानुसार अपडेट कर सकती है, जिससे मूवमेंट सिस्टम को यह कहने की अनुमति मिलती है कि "मुझे कहां आवश्यकता है?" आगे जाओ ” हम अब इन चिंताओं को पूरी तरह से अलग कर सकते हैं, और उनके बारे में और अधिक प्रभावी ढंग से तर्क कर सकते हैं। आंदोलन को रास्ता खोजने की जरूरत नहीं है, बस आपको वहां पहुंचने की जरूरत है।
आप सिस्टम के कुछ हिस्सों को बाहर की ओर उजागर करना चाहते हैं। अपने Pathfinder
सिस्टम में आप शायद एक चाहते हैं Vector2 NextPosition(int entity)
। इस तरह, आप उन तत्वों को कसकर नियंत्रित सरणियों या सूचियों में रख सकते हैं। आप छोटे, struct
प्रकारों का उपयोग कर सकते हैं , जो आपको छोटे, सन्निहित मेमोरी ब्लॉकों में घटकों को रखने में मदद कर सकते हैं, जो सिस्टम अपडेट को बहुत तेज कर सकते हैं । (विशेषकर यदि किसी सिस्टम पर बाहरी प्रभाव कम से कम हो, तो अब उसे केवल आंतरिक स्थिति की देखभाल करने की आवश्यकता है, जैसे कि Name
।)
लेकिन, और मैं इस पर जोर नहीं दे सकता, अब एक Entity
सिर्फ एक है ID
, जिसमें टाइल, ऑब्जेक्ट्स आदि शामिल हैं। यदि कोई इकाई किसी सिस्टम से संबंधित नहीं है, तो सिस्टम इसे ट्रैक नहीं करेगा। इसका मतलब है कि हम अपनी "ट्री" ऑब्जेक्ट बना सकते हैं, उन्हें Sprite
और Movement
सिस्टम में स्टोर कर सकते हैं (पेड़ हिलेंगे नहीं, लेकिन उनके पास "स्थिति" घटक है), और उन्हें अन्य सिस्टम से बाहर रखें। हमें अब पेड़ों के लिए एक विशेष सूची की आवश्यकता नहीं है, क्योंकि एक पेड़ को प्रदान करना एक चरित्र से अलग नहीं है, एक तरफ पेपरडॉलिंग से अलग है। (जिसे Sprite
सिस्टम नियंत्रित कर सकता है, या Paperdoll
सिस्टम नियंत्रित NextPosition
कर सकता है ।) अब हमारा थोड़ा फिर से लिखा जा सकता है: Vector2? NextPosition(int entity)
और यह उन null
संस्थाओं के लिए एक स्थिति वापस कर सकता है जिनके बारे में परवाह नहीं है। हम NameSystem.GetName(int entity)
इसे हमारे लिए भी लागू करते हैं , यह null
पेड़ों और चट्टानों के लिए लौटता है ।
मैं इसे एक करीब से आकर्षित करूंगा, लेकिन यहां विचार आपको ईसीएस पर कुछ पृष्ठभूमि देने के लिए है, और आप अपने गेम पर बेहतर डिजाइन देने के लिए वास्तव में इसका लाभ कैसे उठा सकते हैं । आप प्रदर्शन बढ़ा सकते हैं, असंबंधित तत्वों को कम कर सकते हैं, और चीजों को अधिक संगठित फैशन में रख सकते हैं। (यह भी F # और LINQ की तरह कार्यात्मक भाषाओं / सेटअपों के साथ अच्छी तरह से जोड़ते हैं, जो कि मैं F # की जाँच करने की अत्यधिक सलाह देता हूं यदि आप पहले से नहीं हैं, तो यह C # के साथ बहुत अच्छी तरह से जोड़ते हैं जब आप उन्हें संयोजन में उपयोग करते हैं।)