मैं अपने मेकअप-स्टैटिक-एंड-ग्लोबल डिज़ाइन पैटर्न से छुटकारा पाना चाहता हूं, लेकिन कैसे?


11

मैं अंतरिक्ष में एक छोटे से कालकोठरी क्रॉलर बना रहा हूं, और मैं कुछ सलाह सुनना चाहता हूं कि इंजन के बैकएंड को कैसे बनाया जाए। मूल रूप से, वर्तमान में सब कुछ प्रबंधकों के बकवास पर आधारित है:

  • BackgroundManager: AddBackground(image, parallax)शांत पृष्ठभूमि प्रभाव बनाने की विधि है।
  • ConfigManager: कॉन्फिग फाइल को पढ़ता है / बनाता है और उस कॉन्फिग फाइल से पढ़े गए डेटा को भी रखता है।
  • DrawManager: Draw(sprite)स्क्रीन पर सामान खींचने के लिए विधि, और जैसी चीजें हैं SetView(view), GetView()आदि।
  • EntityManager: सभी सक्रिय इकाइयाँ रखता है और इसमें संस्थाओं को जोड़ने, हटाने और खोजने की विधियाँ हैं।
  • DungeonManager (वास्तव में एक GridManager कहा जाता है, लेकिन इस सादगी के लिए है): है तरीकों की तरह GenerateDungeon(), PlaceEnemies(), PlaceFinish()आदि

अब मैं अपने सभी प्रबंधकों को सूचीबद्ध करने में आधा भी नहीं हूं, इसलिए मुझे लगता है कि इसे बदलना होगा। मेरा गेम भी स्क्रीन पर आधारित है, जो इसे अधिक कष्टप्रद बनाता है क्योंकि मुझे उन आधे सामान की ज़रूरत नहीं है, जो मेरे प्रबंधक संभाल रहे हैं, उदाहरण के लिए, मुख्य मेनू (मुझे अपने मुख्य मेनू में भौतिकी / संस्थाओं / काल कोठरी की आवश्यकता नहीं है) !)

अब मैंने प्रबंधकों को स्थिर नहीं बनाने के बारे में सोचा और अपने स्क्रीनमैनेम को सभी गेम-विशिष्ट प्रबंधकों का उदाहरण दिया। लेकिन यह कॉलिंग / प्रबंधकों से संबंधित कुछ भी प्राप्त करता है एक बड़ी गड़बड़ी ... उदाहरण के लिए, अगर मैं किसी भी जगह से अपने कालकोठरी को आकर्षित करना चाहता था, तो मुझे ScreenMainGame.Draw()यह करना होगा ...

((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()

यह वास्तव में बदसूरत है।

तो, साथी खेल डेवलपर्स, आप में से किसी को भी इस गंदगी को हल करने के लिए एक विचार है? मुझे सराहना मिलेगी!


मुझे यकीन नहीं है कि आपकी मदद कैसे की जाए, लेकिन मैं डिजाइन पैटर्न पर एक अच्छी किताब पढ़ने की सलाह दूंगा। मैं हेड फर्स्ट डिज़ाइन पैटर्न पढ़ रहा हूं और इसे समझना बहुत आसान है। उदाहरण जावा में हैं, लेकिन मुझे लगता है कि आपकी मदद करने के लिए सी # के काफी करीब होगा। क्षमा करें यदि मेरा सुझाव बहुत ही नौसिखिया है।
Amplify91

आप ग्राफिक्स कार्ड के साथ इंटरफेस का उपयोग कर रहे हैं? XNA? SlimDX?
ब्लूराजा - डैनी पफ्लुगुएफ्ट

@ ब्ल्यूराज: मैं एसएफएमएल.नेट का उपयोग कर रहा हूं।
Dlaor

उस स्थिति में, आपको सी # में इन समस्याओं से निपटने के सामान्य तरीकों का उपयोग करना चाहिए: नीचे मेरा अंतिम लिंक देखें, साथ ही निर्भरता इंजेक्शन क्या है?
ब्लूराजा - डैनी पफ्लुगुएफ्ट

जवाबों:


10

घटक-आधारित इंजन के बारे में क्या ?

आपके पास एक मुख्य वर्ग Engineहोगा, जो एक सूची रखेगा GameScreens, जो स्वयं की एक सूची रखेगा Components

इंजन एक है Updateऔर एक Drawतरीका है और दोनों कॉल GameScreenकी Updateऔर Drawविधियों, जो खुद को हर घटक और कॉल के माध्यम से जाना Updateऔर Draw

इस तरह प्रस्तुत, मैं सहमत हूं कि यह एक खराब और दोहरावदार डिजाइन की तरह लगता है। लेकिन मेरा विश्वास करो, मेरे सभी पुराने प्रबंधक वर्गों के साथ घटक-आधारित दृष्टिकोण का उपयोग करके मेरा कोड बहुत अधिक साफ हो गया ।

इस तरह के कोड को बनाए रखना बहुत सरल है, क्योंकि आप सिर्फ एक बड़े वर्ग के पदानुक्रम से गुजर रहे हैं और BackgroundManagerसभी विशिष्ट विभिन्न पृष्ठभूमि के लिए खोज नहीं कर रहे हैं । तुम सिर्फ एक है ScrollingBackground, ParallaxBackground, StaticBackground, आदि जो सभी एक से निकाले जाते हैं Backgroundवर्ग।

आप अंततः एक बहुत ही ठोस इंजन का निर्माण करेंगे, जिसका उपयोग आप अपनी सभी परियोजनाओं पर बहुत अधिक उपयोग किए जाने वाले घटकों और सहायक तरीकों के साथ कर सकते हैं (जैसे FrameRateDisplayerकि डिबगिंग उपयोगिता के रूप में, एक Spriteवर्ग के रूप में एक बुनियादी स्प्राइट और वैक्टर के लिए विस्तार विधियों के साथ। (यादृच्छिक संख्या पीढ़ी)।

अब आपके पास एक BackgroundManagerवर्ग नहीं होगा , लेकिन एक Backgroundवर्ग जो इसके बजाय खुद का प्रबंधन करेगा।

जब आपका खेल शुरू होता है, तो आपको बस यही करना होता है:

// when declaring variables:
Engine engine;

// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());

// when updating:
engine.Update();

// when drawing:
engine.Draw();

और यह आपके गेम स्टार्ट कोड के लिए है।

फिर, मुख्य मेनू स्क्रीन के लिए:

class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
    const int ENEMY_COUNT = 10;

    StaticBackground background;
    Player player;
    List<Enemy> enemies;

    public override void Initialize()
    {
        background = new StaticBackground();
        player = new Player();
        enemies = new List<Enemy>();

        base.AddComponent(background); // defined within the GameScreen class
        base.AddComponent(player);
        for (int i = 0; i < ENEMY_COUNT; ++i)
        {
            Enemy newEnemy = new Enemy();
            enemies.Add(newEnemy);
            base.AddComponent(newEnemy);
        }
    }
}

आप सामान्य विचार प्राप्त करें।

आप Engineअपनी सभी GameScreenकक्षाओं के भीतर का संदर्भ भी रखेंगे , ताकि एक GameScreenवर्ग के भीतर भी नई स्क्रीन को जोड़ सकें (जैसे कि जब उपयोगकर्ता आपके भीतर StartGame बटन पर क्लिक करता है MainMenuScreen, तो आप संक्रमण कर सकते हैं GameplayScreen)।

वही Componentकक्षा के लिए जाता है : उसे अपने माता-पिता के संदर्भ को धारण करना चाहिए GameScreen, नए घटकों को जोड़ने के लिए Engineकक्षा और उसके अभिभावक दोनों के पास होना चाहिए GameScreen(जैसे कि आप एक HUD से संबंधित वर्ग बना सकते हैं जिसे DrawableButtonएक DrawableTextघटक और एक StaticBackgroundघटक कहते हैं)।

आप इसके बाद अन्य डिज़ाइन पैटर्न भी लागू कर सकते हैं, जैसे "सर्विस डिज़ाइन पैटर्न" (सटीक नाम के बारे में निश्चित नहीं) जहां आप अपनी Engineकक्षा के भीतर विभिन्न उपयोगी सेवाएं रख सकते हैं (आप बस अपनी सूची बनाकर रख सकते हैं IServiceऔर अन्य कक्षाओं को स्वयं सेवाओं को जोड़ने दें )। उदाहरण के लिए, मैं Camera2Dअपने सभी प्रोजेक्ट पर एक घटक को एक सेवा के रूप में रखूंगा जब अन्य घटकों को आरेखित करने के लिए इसके परिवर्तन को लागू किया जा सके। यह हर जगह इसे एक पैरामीटर के रूप में पारित करने से बचा जाता है।

निष्कर्ष में, निश्चित रूप से एक इंजन के लिए अन्य बेहतर डिजाइन हो सकते हैं, लेकिन मैंने इस लिंक द्वारा प्रस्तावित इंजन को बहुत सुरुचिपूर्ण, बेहद आसानी से बनाए रखने योग्य और पुन: प्रयोज्य पाया। मैं व्यक्तिगत रूप से इसे कम से कम आजमाने की सलाह दूंगा।


1
XNA इस आउट-ऑफ-द-बॉक्स को GameComponents और सेवाओं के माध्यम से समर्थन करता है। अलग Engineवर्ग की जरूरत नहीं ।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

इस उत्तर के लिए +1। इसके अलावा, गेम अपडेट थ्रेड से ड्राइंग को एक अलग धागे में रखना समझदारी होगी?
f20k

1
@BlueRaja - DannyPflughoeft: वास्तव में, लेकिन मैंने माना कि XNA का उपयोग नहीं किया गया था इसलिए मैंने इसे कैसे करना है, इसके बारे में थोड़ा और विस्तार से बताया।
जेसी इमोंड जूल 29'11

@ f20k: हाँ, ठीक उसी तरह से जैसे XNA करता है। मुझे नहीं पता कि इसे कैसे लागू किया जाता है। = / यह कैसे करना है के बारे में इंटरनेट पर कहीं न कहीं एक लेख होना चाहिए। :)
जेसी इमोंड जूल 29'11

हाँ, मैं XNA का उपयोग नहीं कर रहा हूँ, लेकिन यह एक अच्छा विकल्प की तरह लगता है कि मैं क्या कर रहा हूँ। मैं वर्तमान में "हेड फर्स्ट डिज़ाइन पैटर्न" पुस्तक पढ़ रहा हूं, यह देखने के लिए कि क्या कोई और विकल्प हैं। चीयर्स!
दलेर

1

आप जो करना चाहते हैं वह आपके कोड को घटकों और सेवाओं में अलग करता है। XNA ने इन के लिए पहले से ही अंतर्निहित समर्थन किया है।

इस लेख को GameComponentsऔर सेवाओं पर देखें । फिर XNA में सेवाओं का उपयोग करने पर इस उत्तर को देखें , और किसी भी भाषा में सेवाओं पर यह अधिक सामान्य उत्तर


-3

सिर्फ इसलिए कि वे स्थिर या वैश्विक हैं इसका मतलब यह नहीं है कि उन्हें हमेशा लोड / इनिशियलाइज़ किया जाना चाहिए। एक सिंगलटन पैटर्न का उपयोग करें और प्रबंधकों को फ्रीवेबल और मांग पर फिर से लोड करने की अनुमति दें।


4
एक सिंगलटन सिर्फ एक समस्या है जिसे ओपी यहां हल करने की कोशिश कर रहा है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.