टिप्पणियों में, मैंने अपने उत्तर पुराने उत्तर का एक संक्षिप्त संस्करण पोस्ट किया:
DrawableGameComponent
ताले का उपयोग करके आप एक एकल विधि हस्ताक्षर और एक विशिष्ट बनाए रखा डेटा मॉडल बनाते हैं। ये आमतौर पर शुरू में गलत विकल्प होते हैं, और लॉक-इन महत्वपूर्ण रूप से कोड के विकास में बाधा डालते हैं।
यहाँ मैं यह बताने का प्रयास करूँगा कि मेरे वर्तमान प्रोजेक्ट से कुछ कोड पोस्ट करके ऐसा क्यों है।
खेल की दुनिया की स्थिति को बनाए रखने वाली जड़ वस्तु में एक Update
विधि है जो इस तरह दिखाई देती है:
void Update(UpdateContext updateContext, MultiInputState currentInput)
Update
खेल में नेटवर्क पर चल रहा है या नहीं, इसके आधार पर कई प्रवेश-बिंदु हैं। यह संभव है, उदाहरण के लिए, खेल राज्य को समय में एक पिछले बिंदु पर वापस ले जाने के लिए और फिर से सिम्युलेटेड।
कुछ अतिरिक्त अपडेट जैसी विधियां भी हैं, जैसे:
void PlayerJoin(int playerIndex, string playerName, UpdateContext updateContext)
खेल राज्य के भीतर अद्यतन किए जाने वाले अभिनेताओं की एक सूची है। लेकिन यह एक साधारण Update
कॉल से अधिक है । भौतिकी को संभालने के पहले और बाद में अतिरिक्त पास हैं। अभिनेताओं के स्थगित / नष्ट करने के साथ-साथ स्तर परिवर्तन के लिए कुछ फैंसी सामान भी हैं।
खेल राज्य के बाहर, एक यूआई प्रणाली है जिसे स्वतंत्र रूप से प्रबंधित करने की आवश्यकता है। लेकिन UI में कुछ स्क्रीन को नेटवर्क के संदर्भ में भी चलाने में सक्षम होना चाहिए।
ड्राइंग के लिए, खेल की प्रकृति के कारण, एक कस्टम सॉर्टिंग और पुलिंग प्रणाली है जो इन विधियों से इनपुट लेती है:
virtual void RegisterToDraw(SortedDrawList sortedDrawList, Definitions definitions)
virtual void RegisterShadow(ShadowCasterList shadowCasterList, Definitions definitions)
और फिर, एक बार यह पता लग जाए कि क्या खींचना है, स्वचालित रूप से कॉल करें:
virtual void Draw(DrawContext drawContext, int tag)
tag
पैरामीटर की आवश्यकता है, क्योंकि कुछ अभिनेताओं अन्य अभिनेताओं पर पकड़ कर सकते हैं - और इसलिए जरूरत दोनों के ऊपर और नीचे रखे हुए अभिनेता आकर्षित करने के लिए सक्षम होने के लिए। छँटाई प्रणाली सुनिश्चित करती है कि यह सही क्रम में होता है।
ड्रॉ करने के लिए मेनू सिस्टम भी है। और खेल के चारों ओर, HUD के आसपास, UI को चित्रित करने के लिए एक पदानुक्रमित प्रणाली।
अब उन आवश्यकताओं की तुलना करें जो DrawableGameComponent
प्रदान करती हैं:
public class DrawableGameComponent
{
public virtual void Update(GameTime gameTime);
public virtual void Draw(GameTime gameTime);
public int UpdateOrder { get; set; }
public int DrawOrder { get; set; }
}
DrawableGameComponent
ऊपर वर्णित प्रणाली का उपयोग करके सिस्टम से प्राप्त करने का कोई उचित तरीका नहीं है। (और मामूली जटिलता के एक खेल के लिए वे असामान्य आवश्यकताएं नहीं हैं)।
इसके अलावा, यह ध्यान रखना बहुत महत्वपूर्ण है कि उन आवश्यकताओं को परियोजना की शुरुआत में बस-अप नहीं किया गया था। वे कई महीनों के विकास कार्य में विकसित हुए।
लोग आमतौर पर क्या करते हैं, अगर वे DrawableGameComponent
मार्ग को शुरू करते हैं, तो क्या वे हैक पर निर्माण करना शुरू करते हैं:
तरीकों को जोड़ने के बजाय, वे अपने स्वयं के आधार प्रकार के लिए कुछ बदसूरत डाउन-कास्टिंग करते हैं (केवल सीधे उपयोग क्यों नहीं करते?)।
छँटाई और आह्वान Draw
/ के लिए कोड को बदलने के बजाय Update
, वे कुछ बहुत धीमी गति से आदेश संख्याओं को बदलने के लिए करते हैं।
और सभी के लिए सबसे खराब: तरीकों में मापदंडों को जोड़ने के बजाय, वे मेमोरी स्थानों में "पास" "पैरामीटर" शुरू करते हैं जो स्टैक नहीं हैं (इसके लिए उपयोग Services
लोकप्रिय है)। यह जटिल है, त्रुटि-प्रवण, धीमा, नाजुक, शायद ही कभी थ्रेड-सेफ, और यदि आप नेटवर्किंग जोड़ते हैं, तो बाहरी उपकरण, और इसी तरह एक समस्या बनने की संभावना है।
यह कोड को फिर से उपयोग में कठिन बनाता है , क्योंकि अब आपकी निर्भरता "घटक" के अंदर छिपी हुई है, बजाय एपीआई सीमा पर प्रकाशित होने के।
या, वे लगभग देखते हैं कि यह सब कितना पागल है, और DrawableGameComponent
इन समस्याओं के आसपास काम करने के लिए "प्रबंधक" करना शुरू करें । सिवाय उनके अभी भी "प्रबंधक" सीमाओं पर ये समस्याएं हैं।
वांछित क्रम में इन "प्रबंधकों" को आसानी से विधि कॉल की एक श्रृंखला के साथ बदला जा सकता है। और कुछ भी जटिल नहीं है।
बेशक, एक बार जब आप उन हैक्स को नियोजित करना शुरू करते हैं, तो यह उन हैक को पूर्ववत करने के लिए वास्तविक काम लेता है जब आपको एहसास होता है कि आपको क्या DrawableGameComponent
प्रदान करता है। आप " लॉक इन " हो जाते हैं । और प्रलोभन को अक्सर हैक पर ढेर करना जारी रखना होता है - जो व्यवहार में आपको नीचे गिरा देगा और उन खेलों के प्रकारों को सीमित कर देगा जिन्हें आप अपेक्षाकृत सरल बना सकते हैं।
बहुत सारे लोग इस बिंदु तक पहुंचते हैं और एक आंत प्रतिक्रिया होती है - संभवतः क्योंकि वे उपयोग करते हैं DrawableGameComponent
और "गलत" होने को स्वीकार नहीं करना चाहते हैं। इसलिए वे इस तथ्य पर ध्यान देते हैं कि इसे "काम" करना कम से कम संभव है।
बेशक इसे "काम" किया जा सकता है ! हम प्रोग्रामर हैं - असामान्य बाधाओं के तहत काम करना व्यावहारिक रूप से हमारा काम है। लेकिन यह संयम आवश्यक, उपयोगी या तर्कसंगत नहीं है ...
इसके बारे में विशेष रूप से भड़कीला है कि यह इस पूरे मामले को साइड-स्टेप करने के लिए आश्चर्यजनक रूप से तुच्छ है। यहाँ, मैं आपको कोड भी दूंगा:
public class Actor
{
public virtual void Update(GameTime gameTime);
public virtual void Draw(GameTime gameTime);
}
List<Actor> actors = new List<Actor>();
foreach(var actor in actors)
actor.Update(gameTime);
foreach(var actor in actors)
actor.Draw(gameTime);
(यह आसान के अनुसार छँटाई में जोड़ने के लिए DrawOrder
और UpdateOrder
। एक आसान तरीका दो सूचियों, और उपयोग को बनाए रखना है List<T>.Sort()
। यह भी संभाल करने के लिए मामूली बात है Load
/ UnloadContent
।)
यह महत्वपूर्ण नहीं है कि वास्तव में वह कोड क्या है । यह महत्वपूर्ण है कि मैं इसे तुच्छ रूप से संशोधित कर सकता हूं ।
जब मुझे पता चलता है कि मुझे एक अलग समय प्रणाली की gameTime
आवश्यकता है, या मुझे अधिक मापदंडों (या UpdateContext
इसमें लगभग 15 चीजों के साथ एक संपूर्ण ऑब्जेक्ट) की आवश्यकता है, या मुझे ड्राइंग के लिए पूरी तरह से अलग-अलग ऑर्डर-ऑफ-ऑपरेशन की आवश्यकता है, या मुझे कुछ अतिरिक्त तरीकों की आवश्यकता है अलग-अलग अपडेट पास के लिए, मैं अभी आगे जाकर ऐसा कर सकता हूं ।
और मैं इसे तुरंत कर सकता हूं। मुझे DrawableGameComponent
अपने कोड से बाहर निकालने के बारे में बताने की आवश्यकता नहीं है । या इससे भी बदतर: इसे किसी तरह से हैक करें जो अगली बार इस तरह की आवश्यकता के आसपास भी कठिन हो जाएगा।
वास्तव में केवल एक ही परिदृश्य है जहां यह उपयोग करने के लिए एक अच्छा विकल्प है DrawableGameComponent
: और यदि आप शाब्दिक रूप से XNA के लिए ड्रैग-एंड-ड्रॉप-घटक-शैली मिडलवेयर बना रहे हैं और प्रकाशित कर रहे हैं । जो इसका मूल उद्देश्य था। जो - मैं जोड़ूंगा - कोई नहीं कर रहा है!
(इसी तरह, यह केवलServices
कस्टम सामग्री प्रकार बनाते समय उपयोग करने के लिए वास्तव में समझ में आता हैContentManager
।)