शीर्षक जानबूझकर अतिशयोक्तिपूर्ण है और यह सिर्फ पैटर्न के साथ मेरी अनुभवहीनता हो सकती है लेकिन यहाँ मेरा तर्क है:
संस्थाओं को लागू करने का "सामान्य" या यकीनन सीधा तरीका उन्हें वस्तुओं के रूप में लागू करना और सामान्य व्यवहार को उपवर्गित करना है। की क्लासिक समस्या के लिए यह होता है "एक है EvilTree
की एक उपवर्ग Tree
या Enemy
?"। यदि हम कई विरासत की अनुमति देते हैं, तो हीरे की समस्या पैदा होती है। हम इसके बजाय संयुक्त कार्यप्रणाली को आगे बढ़ा सकते हैं Tree
और Enemy
आगे चलकर पदानुक्रम को बढ़ा सकते हैं जो ईश्वर वर्गों की ओर जाता है, या हम जानबूझकर अपने Tree
और Entity
कक्षाओं में व्यवहार को छोड़ सकते हैं (उन्हें चरम मामले में इंटरफेस बना EvilTree
सकते हैं ) ताकि खुद को लागू किया जा सके - जो आगे बढ़ता है कोड दोहराव अगर हम कभी भी एक SomewhatEvilTree
।
इकाई-घटक प्रणाली को विभाजित करके इस समस्या को हल करने का प्रयास करें Tree
और Enemy
विभिन्न घटकों में वस्तु - कहते हैं Position
, Health
और AI
- और लागू इस तरह के एक के रूप में प्रणाली, AISystem
कि ऐ निर्णय के अनुसार एक Entitiy की स्थिति बदल जाती है। अब तक तो अच्छा है लेकिन क्या हो EvilTree
सकता है अगर कोई पॉवरअप उठा सकता है और नुकसान का सामना कर सकता है? पहले हमें एक की जरूरत है CollisionSystem
और DamageSystem
(हम शायद पहले से ही ये हैं)। इसके CollisionSystem
साथ संवाद करने की आवश्यकताएं DamageSystem
: हर बार दो चीजें CollisionSystem
एक संदेश को भेजती हैं DamageSystem
ताकि यह स्वास्थ्य को घटा सके। नुकसान पॉवरअप से भी प्रभावित होता है इसलिए हमें इसे कहीं स्टोर करने की आवश्यकता है। क्या हम एक नया बनाते हैं PowerupComponent
जिसे हम संस्थाओं से जोड़ते हैं? लेकिन फिर दDamageSystem
इसके बारे में कुछ जानने की जरूरत है, इसके बारे में कुछ नहीं जानना चाहिए - आखिरकार, ऐसी चीजें भी हैं जो नुकसान का सौदा करती हैं जो पावरअप (जैसे Spike
) नहीं उठा सकती हैं । क्या हम इस उत्तर के समान क्षति गणना के लिए भी इसे PowerupSystem
संशोधित करने की अनुमति देते हैं ? लेकिन अब दो सिस्टम एक ही डेटा को एक्सेस करते हैं। जैसा कि हमारा खेल अधिक जटिल हो जाता है, यह एक अमूर्त निर्भरता ग्राफ बन जाएगा, जहां कई प्रणालियों के बीच घटक साझा किए जाते हैं। उस बिंदु पर हम सिर्फ वैश्विक स्थिर चर का उपयोग कर सकते हैं और सभी बॉयलरप्लेट से छुटकारा पा सकते हैं।StatComponent
क्या इसे हल करने का कोई प्रभावी तरीका है? एक विचार मुझे घटकों को कुछ कार्य करने देना था, उदाहरण के लिए, StatComponent
attack()
जो डिफ़ॉल्ट रूप से पूर्णांक देता है, लेकिन जब एक पावरअप हो सकता है:
attack = getAttack compose powerupBy(20) compose powerdownBy(40)
यह उस समस्या को हल नहीं करता attack
है जिसे कई प्रणालियों द्वारा एक्सेस किए गए घटक में सहेजा जाना चाहिए, लेकिन कम से कम मैं फ़ंक्शन ठीक से टाइप कर सकता हूं अगर मेरे पास एक भाषा है जो इसे पर्याप्त रूप से समर्थन करती है:
// In StatComponent
type Strength = PrePowerup | PostPowerup
type Damage = Int
type PrePowerup = Int
type PostPowerup = Int
attack: Strength = getAttack //default value, can be changed by systems
getAttack: PrePowerup
// these functions can be defined in other components or in PowerupSystems
powerupBy: Strength -> PostPowerup
powerdownBy: Strength -> PostPowerup
subtractArmor: Strength -> Damage
// in DamageSystem
dealDamage: Damage -> () = attack compose subtractArmor compose hurtSomeEntity
इस तरह मैं कम से कम सिस्टम द्वारा जोड़े गए विभिन्न कार्यों के सही क्रम की गारंटी देता हूं। किसी भी तरह से, ऐसा लगता है कि मैं तेजी से कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग के लिए यहां आ रहा हूं इसलिए मैं खुद से पूछता हूं कि क्या मुझे शुरू से ही इसका इस्तेमाल नहीं करना चाहिए था (मैंने केवल एफआरपी में देखा है, इसलिए मैं यहां गलत हो सकता हूं)। मैं देखता हूं कि ईसीएस जटिल वर्ग पदानुक्रमों में सुधार है, लेकिन मैं आश्वस्त नहीं हूं कि यह आदर्श है।
क्या इसके आसपास कोई हल है? क्या ECS को अधिक साफ-सुथरा बनाने के लिए एक कार्यक्षमता / पैटर्न मुझे याद आ रहा है? क्या इस समस्या के लिए एफआरपी केवल कड़ाई से बेहतर है? क्या ये समस्याएँ जो मैं कार्यक्रम करने की कोशिश कर रहा हूँ, उसमें निहित जटिलता से उत्पन्न हो रही है; यानी एफआरपी के समान मुद्दे होंगे?