मैं थोड़ी देर के लिए 2d आरपीजी पर काम कर रहा हूं, और मुझे पता चला है कि मैंने कुछ खराब डिजाइन निर्णय लिए हैं। विशेष रूप से कुछ चीजें हैं जो मुझे समस्याएं पैदा कर रही हैं, इसलिए मैं सोच रहा था कि अन्य लोग उन्हें दूर करने के लिए किस तरह के डिजाइन का उपयोग करते हैं या उपयोग करेंगे।
थोड़ी सी पृष्ठभूमि के लिए, मैंने पिछली गर्मियों में अपने खाली समय में इस पर काम करना शुरू किया। मैं शुरू में C # में गेम बना रहा था, लेकिन लगभग 3 महीने पहले, C ++ में स्विच करने का फैसला किया। मैं सी ++ पर एक अच्छा हैंडल प्राप्त करना चाहता था क्योंकि यह थोड़ी देर से है क्योंकि मैंने इसका भारी उपयोग किया है, और लगा कि यह एक अच्छा प्रेरक होगा। मैं बड़े पैमाने पर बूस्ट लाइब्रेरी का उपयोग कर रहा हूं और ऑडियो के लिए ग्राफिक्स और एफएमओडी के लिए एसएफएमएल का उपयोग कर रहा हूं।
मेरे पास कोड लिखा हुआ है, लेकिन मैं इसे खत्म करने और शुरू करने पर विचार कर रहा हूं।
यहां चिंता के प्रमुख क्षेत्र हैं जो मैं चाहता हूं कि कुछ लोगों ने उचित तरीके से कुछ राय प्राप्त की है और उन्हें हल किया है।
1. चक्रीय निर्भरता जब मैं C # में खेल कर रहा था, तो मुझे वास्तव में इस बारे में चिंता करने की आवश्यकता नहीं थी क्योंकि यह कोई मुद्दा नहीं है। C ++ में जाना, यह एक बहुत बड़ी समस्या बन गई है और मुझे लगता है कि मैंने चीजों को गलत तरीके से डिजाइन किया होगा। मैं वास्तव में कल्पना नहीं कर सकता कि मैं अपनी कक्षाओं को कैसे समाप्त कर सकता हूं और अभी भी उन्हें वही करना है जो मैं चाहता हूं। यहां निर्भरता श्रृंखला के कुछ उदाहरण दिए गए हैं:
मेरे पास एक स्थिति प्रभाव वर्ग है। किसी वर्ण के विरुद्ध प्रभाव लागू करने के लिए वर्ग में कई विधियाँ हैं (लागू करें / लागू करें, टिक करें, आदि)। उदाहरण के लिए,
virtual void TickCharacter(Character::BaseCharacter* character, Battles::BattleField *field, int ticks = 1);
इस कार्य को हर बार कहा जाता है कि स्थिति प्रभाव से भरा चरित्र एक मोड़ लेता है। इसका उपयोग रेगेन, ज़हर आदि जैसे प्रभावों को लागू करने के लिए किया जाएगा। हालाँकि, यह बेसचेचर क्लास और बैटलफिल्ड क्लास पर निर्भरता का भी परिचय देता है। स्वाभाविक रूप से, बेसचेचर वर्ग को इस बात पर नज़र रखने की आवश्यकता है कि वर्तमान में उन पर क्या प्रभाव है ताकि यह एक चक्रीय निर्भरता हो। युद्ध के मैदान में लड़ाई करने वाले दलों पर नज़र रखने की आवश्यकता होती है, और पार्टी वर्ग के पास एक और चक्रीय निर्भरता की शुरुआत करने वाले बेसचेकर्स की एक सूची है।
2 - घटनाएँ
C # में मैंने वर्णों, युद्ध क्षेत्रों आदि पर घटनाओं में हुक लगाने के लिए प्रतिनिधियों का व्यापक उपयोग किया (उदाहरण के लिए, चरित्र के स्वास्थ्य में परिवर्तन, जब एक स्टेटस इफेक्ट जोड़ा गया / हटाया गया, इत्यादि के लिए एक प्रतिनिधि था। ।) और युद्धक्षेत्र / चित्रमय घटक अपने प्रभाव को लागू करने के लिए उन प्रतिनिधियों को हुक करेंगे। C ++ में, मैंने कुछ ऐसा ही किया। जाहिर है कि सी # प्रतिनिधियों के बराबर कोई प्रत्यक्ष नहीं है, इसलिए इसके बजाय मैंने कुछ इस तरह बनाया:
typedef boost::function<void(BaseCharacter*, int oldvalue, int newvalue)> StatChangeFunction;
और मेरे चरित्र वर्ग में
std::map<std::string, StatChangeFunction> StatChangeEventHandlers;
जब भी चरित्र की प्रतिमा बदली, मैं इटरेट करूंगा और हर स्टेटचेंजफ़ंक्शन को मैप पर कॉल करूंगा। जबकि यह काम करता है, मुझे चिंता है कि यह काम करने के लिए एक बुरा दृष्टिकोण है।
3 - ग्राफिक्स
यह बड़ी बात है। यह मेरे द्वारा उपयोग किए जा रहे ग्राफिक्स लाइब्रेरी से संबंधित नहीं है, लेकिन एक वैचारिक चीज से अधिक है। C # में, मैंने अपनी कक्षाओं में बहुत से ग्राफिक्स जोड़े, जो मुझे पता है कि एक भयानक विचार है। यह करना चाहते थे इस बार मैंने अलग दृष्टिकोण की कोशिश की।
अपने ग्राफिक्स को लागू करने के लिए, मैं गेम से संबंधित सभी ग्राफिक्स को स्क्रीन की एक श्रृंखला के रूप में कल्पना कर रहा था। यानी वहाँ एक शीर्षक स्क्रीन, एक चरित्र स्थिति स्क्रीन, एक मानचित्र स्क्रीन, एक इन्वेंट्री स्क्रीन, एक लड़ाई स्क्रीन, एक लड़ाई जीयूआई स्क्रीन है, और मूल रूप से मैं खेल ग्राफिक्स बनाने के लिए आवश्यक रूप से एक दूसरे के ऊपर इन स्क्रीन को ढेर कर सकता है। जो भी सक्रिय स्क्रीन गेम इनपुट का मालिक है।
मैंने एक स्क्रीन मैनेजर डिज़ाइन किया है जो उपयोगकर्ता इनपुट के आधार पर पुश और पॉप स्क्रीन करेगा।
उदाहरण के लिए, यदि आप एक मानचित्र स्क्रीन पर थे (एक टाइल मानचित्र के लिए एक इनपुट हैंडलर / विज़ुअलाइज़र) और प्रारंभ बटन दबाया, तो यह स्क्रीन स्क्रीन पर मुख्य मेनू स्क्रीन को पुश करने और मानचित्र को चिह्नित करने के लिए स्क्रीन प्रबंधक को कॉल जारी करेगा। स्क्रीन को खींचा / अद्यतन नहीं किया जाना चाहिए। खिलाड़ी मेनू के चारों ओर नेविगेट करेगा, जो स्क्रीन स्टैक पर नई स्क्रीन को पुश करने के लिए स्क्रीन प्रबंधक के लिए अधिक कमांड जारी करेगा, फिर उन्हें उपयोगकर्ता स्क्रीन / रद्द करने के लिए पॉप के रूप में पॉप करेगा। अंत में जब खिलाड़ी मुख्य मेनू से बाहर निकलता है, तो मैं इसे बंद कर दूंगा और मैप स्क्रीन पर वापस आ जाऊंगा, टिप्पणी करूंगा कि इसे ड्रा / अपडेट किया जाए और वहां से जाएं।
बैटल स्क्रीन अधिक जटिल होगी। मेरे पास पृष्ठभूमि के रूप में कार्य करने के लिए एक स्क्रीन होगी, लड़ाई में प्रत्येक पार्टी की कल्पना करने के लिए एक स्क्रीन और लड़ाई के लिए UI की कल्पना करने के लिए एक स्क्रीन होगी। यूआई चरित्र घटनाओं में हुक करेगा और यूआई घटकों को अपडेट / रीड्रा करने के लिए निर्धारित करने के लिए उन का उपयोग करेगा। अंत में, हर हमले में एक उपलब्ध एनीमेशन स्क्रिप्ट होती है, जो स्क्रीन स्टैक को बंद करने से पहले एक अतिरिक्त परत को चेतन करने के लिए कहता है। इस मामले में, प्रत्येक परत को लगातार ड्रा करने योग्य और अद्यतन करने योग्य के रूप में चिह्नित किया जाता है और मुझे अपने युद्ध ग्राफिक्स को संभालने वाली स्क्रीन का ढेर मिलता है।
हालांकि मैं स्क्रीन मैनेजर को पूरी तरह से काम करने में सक्षम नहीं कर पाया, लेकिन मुझे लगता है कि मैं कुछ समय के साथ काम कर सकता हूं। इसके बारे में मेरा सवाल यह है कि क्या यह एक सार्थक दृष्टिकोण है? यदि यह एक बुरा डिज़ाइन है जिसे मैं अभी जानना चाहता हूं तो इससे पहले कि मैं अपनी ज़रूरत के अनुसार सभी स्क्रीन बना रहा हूं। आप अपने गेम के लिए ग्राफिक्स कैसे बनाएंगे?