इकाई घटक प्रणाली आधारित इंजन


9

नोट: मैं इसे जावास्क्रिप्ट में प्रोग्रामिंग कर रहा हूं, लेकिन यह अधिकांश भाग में भाषा अज्ञेय होना चाहिए।

मैं अपने इंजन को ईसीएस आधारित एक में परिवर्तित करने के बारे में सोच रहा हूं।

मुझे मूल विचार मिलता है ( ध्यान दें: यह गलत है, मेरा उत्तर देखें ):

संस्थाएं खेल की वस्तुएं हैं।
घटक कार्यक्षमता ( reactToInput()) या राज्य ( position) के बिट हैं जो संस्थाओं को "सरेस से जोड़ा हुआ" प्राप्त कर सकते हैं।
सिस्टम में उन संस्थाओं की एक सूची होती है जिन्हें वे प्रबंधित और अद्यतन करते हैं।

लेकिन, मुझे पूरा यकीन नहीं है कि मुझे कार्यान्वयन और कुछ विवरण मिलते हैं ...

प्रश्न: क्या एक प्रणाली विभिन्न प्रकार की संस्थाओं पर काम कर सकती है? मैं आमतौर पर Sceneअपने इंजन में बुलाए गए एक वर्ग का उदाहरण देता हूं, और यह इस उद्देश्य को अब भी पूरा करेगा। एक दृश्य सभी वस्तुओं का एक कंटेनर होता है जिसे रेंडर किया जा सकता है, अद्यतन किया जा सकता है, प्रतिपादन (रोशनी) को प्रभावित कर सकता है, और शायद, भविष्य में, यहां तक ​​कि 2DSoundEmitterवस्तुओं को भी । इसका एक उच्च-स्तरीय इंटरफ़ेस है, इसलिए उपयोगकर्ता को उस वस्तु के प्रकार के बारे में चिंता करने की आवश्यकता नहीं है जो वह scene.add()आईएनजी है, और उस तरह का सामान।

मुझे एहसास है कि Sceneएक प्रणाली हो सकती है। यह संस्थाओं में लेता है, उन्हें संग्रहीत करता है, और फिर यह उनके अद्यतन तरीकों को कॉल कर सकता है, और शायद कुछ राज्य परिवर्तन भी करता है। लेकिन, एक समस्या है: जैसा कि मैंने ऊपर वर्णित किया है, विभिन्न प्रकार की वस्तुओं को Sceneखिलाया जा सकता है ! मुझे क्या करना चाहिए, कहना चाहिए, एक ऐसी स्थिति जिसमें एक दृश्य में दोनों रेंडर करने योग्य ऑब्जेक्ट ("ड्रॉबल्स") और उसमें रोशनी हो? क्या मुझे बातचीत करने से पहले इसे टाइप-चेक एंटिटीज़ बनाना चाहिए? या, क्या मुझे इसे और भी निचले स्तर पर हल करना चाहिए: एक घटक बनाएं जो किसी भी वस्तु में जोड़ा जा सकता है , और प्रकाश सिर्फ एक इकाई और घटकों के साथ होगा । क्या यह स्वीकार्य है?LightSourceLightSourcePosition

इसके अलावा, क्या यह अभी भी पारंपरिक विरासत और पारंपरिक वर्गों का उपयोग करने के लिए एक अच्छा अभ्यास है? उदाहरण के लिए, मैं अभी समझ नहीं पा रहा हूं कि मेरा क्या होगा Renderer! यह एक प्रणाली नहीं है, क्योंकि इसका एकमात्र कार्य एक कैमरा और एक दृश्य में लेना है, सब कुछ प्रस्तुत करना और प्रभाव (जैसे छाया) लागू करना है। यह संदर्भ, खेल की चौड़ाई और ऊंचाई का भी प्रबंधन करता है, अनुवाद करता है ... लेकिन यह अभी भी एक प्रणाली नहीं है!

संपादित करें: क्या आप शायद ईसीएस पर पाए गए किसी भी संसाधन को लिंक कर सकते हैं? मुझे अच्छे लोगों को खोजने में परेशानी हो रही है।


2
इस पृष्ठ पर उत्तर को फिर से लिखने के बजाय, मैं सिर्फ यह लिंक दूंगा: gamedev.stackexchange.com/questions/23533/… इकाई से व्युत्पन्न नहीं होना चाहिए, संस्थाओं के बीच कोई अंतर घटकों के माध्यम से पूरा किया जाना चाहिए। आम तौर पर आपको प्रत्येक प्रमुख प्रणाली (रेंडरिंग, भौतिकी, नेटवर्किंग, इनपुट, ऑडियो, आदि ...) के लिए एक इंटरफ़ेस की आवश्यकता होगी। जिस तरह से मैंने अपने रेंडर को सेटअप किया है वह रेंडर करने योग्य संस्थाओं के लिए दृश्य को क्वेरी करने के लिए है, और दृश्य प्रबंधक प्रत्येक इकाई से पूछता है कि उसके रेंडर जानकारी के लिए उस पर एक रेंडर घटक है।
निक फोस्टर

1
टी = मशीन ब्लॉग पर घटक डिजाइन (जब से आपने एक अच्छा पूछा है)
जॉन मैकडॉनल्ड

एक इकाई ढांचे का कोड और चर्चा: gamadu.com/artemis
पैट्रिक ह्यूजेस

@JohnMcDonald, मैंने उस लेख पर एक टिप्पणी लिखी है, हालांकि यह मॉडरेशन की प्रतीक्षा कर रहा है। आप इसे यहाँ देख सकते हैं: t-machine.org/index.php/2007/12/22/… । मैं "यनबाने" हूं।
जकोरा

इसके अलावा, @NicFoster, जिस लेख पर जॉन ने T = मशीन से लिंक किया है, वह आपके उत्तर से अलग कुछ प्रकार का वर्णन करता है ... उस डेव के लिए, संस्थाओं के पास घटकों की सूची नहीं है, वे सिर्फ एक नाम हैं। जैसे "flsjn304" - यह एक इकाई है। यह "कहीं न कहीं" संग्रहीत है। और मुझे यह समझने के लिए फिर से पढ़ना होगा कि क्या वह वास्तव में सिस्टम के अंदर घटक रखता है , जो मुझे बहुत अजीब लगता है!
जकोरा

जवाबों:


6

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

सबसे पहले, "OOP का उपयोग न करें" कारक पर, याद रखें कि जावास्क्रिप्ट ऑब्जेक्ट अन्य भाषाओं की तुलना में playdough की तरह हैं और आपको वास्तव में एक cascading-inheritance योजना दुःस्वप्न बनाने के लिए अपने रास्ते से बाहर जाना होगा क्योंकि JS वर्ग नहीं है। -बेड और कंपोजिंग इसके लिए स्वाभाविक रूप से बहुत अधिक आता है। यदि आप अपने जेएस में कुछ मूर्खतापूर्ण वर्ग या प्रोटोटाइप हैंड-मी-डाउन सिस्टम लागू कर रहे हैं, तो इसे खाई पर विचार करें। जेएस में हम क्लोजर, प्रोटोटाइप का उपयोग करते हैं, और हम कैंडी जैसे कार्यों को पास करते हैं। यह घृणित और गंदी और गलत है, लेकिन शक्तिशाली, संक्षिप्त है और यही वह तरीका है जो हमें पसंद है।

विरासत के भारी दृष्टिकोणों को वास्तव में डिज़ाइन पैटर्न में एक विरोधी पैटर्न के रूप में समझा जाता है और अच्छे कारण के रूप में जो कोई भी वर्ग या वर्ग जैसी संरचनाओं के 15+ स्तर से नीचे चला गया है, जहां यह पता लगाने की कोशिश की जाती है कि एक विधि का पर्दाफाश संस्करण कहां है? से आ रहा था आपको बता सकता है।

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

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

  • इकाई - विशिष्ट चीज जिसे आप डिजाइन कर रहे हैं। हम उचित संज्ञा की दिशा में अधिक बात कर रहे हैं (लेकिन वास्तव में, बिल्कुल नहीं)। Not सीन ’नहीं, बल्कि ro इंट्रोएरेवेलीन’। IntroAreaLevelOne किसी तरह के एक दृश्य बॉक्स के अंदर बैठ सकता है, लेकिन हम कुछ विशिष्ट चीजों पर ध्यान केंद्रित कर रहे हैं जो संबंधित चीजों से भिन्न होती हैं। कोड में, एक इकाई वास्तव में सिर्फ एक नाम (या आईडी) है जो सामान के एक समूह से बंधा है जिसे उपयोगी होने के लिए इसे लागू या स्थापित (घटकों) की आवश्यकता है।

  • अवयव - एक इकाई की जरूरत के प्रकार। ये सामान्य संज्ञाएं हैं। वॉकिंगएनिमेशन की तरह। WalkingAnimation के भीतर हम और अधिक विशिष्ट हो सकते हैं, जैसे "शंबलिंग" (लाश और पौधों के राक्षसों के लिए अच्छा विकल्प), या "चिकनवल्कर" (रिवर्स-ज्वाइंट एड -209इश रोबोट-प्रकार के लिए महान)। नोट: यह निश्चित नहीं है कि इस तरह एक 3 डी मॉडल के प्रतिपादन से कैसे कम हो सकता है - इसलिए शायद एक बकवास उदाहरण है, लेकिन मैं एक जेएस समर्थक से अधिक एक अनुभवी खेल देवता हूं। जेएस में मैं घटकों के साथ एक ही बॉक्स में मैपिंग तंत्र लगाऊंगा। अपने आप में घटक तर्क पर हल्के होने की संभावना रखते हैं और आपके सिस्टम को बताए जाने वाले रोडमैप के अधिक होने पर क्या सिस्टम लागू करने की आवश्यकता है (ईसीएस में मेरे प्रयास में कुछ घटक सिर्फ संपत्ति सेट के संग्रह हैं)। एक बार एक घटक स्थापित होने के बाद, यह '

  • सिस्टम - असली प्रोग्राममी मांस यहाँ है। AI सिस्टम बनाया गया है और जुड़ा हुआ है, रेंडरिंग हासिल किया गया है, एनिमेशन सीक्वेंस स्थापित किए गए हैं, आदि ... मैं बाहर नकल कर रहा हूं और ज्यादातर इन कल्पनाओं को छोड़ रहा हूं लेकिन उदाहरण में System.AI गुणों का एक गुच्छा लेता है और एक फ़ंक्शन को थूक देता है जो ईवेंट हैंडलर को ऑब्जेक्ट में जोड़ने के लिए उपयोग किया जाता है जो अंततः कार्यान्वयन में उपयोग किया जाता है। System.AI के बारे में महत्वपूर्ण बात यह है कि इसमें कई घटक प्रकार शामिल हैं। आप एक घटक के साथ सभी एआई सामान को सॉर्ट कर सकते हैं लेकिन ऐसा करने के लिए चीजों को दानेदार बनाने की बात को गलत समझना है।

माइंड्स गोल्स: हम गैर-डिजाइनरों के लिए कुछ प्रकार के GUI इंटरफ़ेस में प्लग-इन करना आसान बनाना चाहते हैं, एक प्रतिमान के भीतर घटकों को अधिकतम और मिलान करके विभिन्न प्रकार के सामान को आसानी से ट्विस्ट कर सकते हैं, जो उन्हें समझ में आता है, और हम इससे दूर होना चाहते हैं लोकप्रिय मनमाने ढंग से कोड योजनाएं जो संशोधित करने या बनाए रखने की तुलना में बहुत आसान हैं।

तो जेएस में, शायद कुछ इस तरह। खेल देवता कृपया मुझे बताएं कि क्या मुझे यह बहुत गलत लगा है:

//I'm going with simple objects of flags over arrays of component names
//easier to read and can provide an opt-out default
//Assume a genre-bending stealth assassin game

//new (function etc... is a lazy way to define a constructor and auto-instantiate
var npcEntities = new (function NpcEntities(){

    //note: {} in JS is an object literal, a simple obj namespace (a dictionary)
    //plain ol' internal var in JS is akin to a private member
    var default={ //most NPCs are humanoids and critters - why repeat things?
        speedAttributes:true,
        maneuverAttributes:true,
        combatAttributes:true,
        walkingAnimation:true,
        runningAnimation:true,
        combatAnimation:true,
        aiOblivious:true,
        aiAggro:true,
        aiWary:true, //"I heard something!"
        aiFearful:true
    };

    //this. exposes as public

    this.zombie={ //zombies are slow, but keep on coming so don't need these
        runningAnimation:false,
        aiFearful:false
    };

    this.laserTurret={ //most defaults are pointless so ignore 'em
        ignoreDefault:true,
        combatAttributes:true,
        maneuverAttrubtes:true, //turning speed only
    };
    //also this.nerd, this.lawyer and on and on...

    //loop runs on instantiation which we're forcing on the spot

    //note: it would be silly to repeat this loop in other entity collections
    //but I'm spelling it out to keep things straight-forward.
    //Probably a good example of a place where one-level inheritance from
    //a more general entity class might make sense with hurting the pattern.
    //In JS, of course, that would be completely unnecessary. I'd just build a
    //constructor factory with a looping function new objects could access via
    //closure.

    for(var x in npcEntities){

        var thisEntity = npcEntities[x];

        if(!thisEntity.ignoreDefaults){

            thisEntity = someObjectXCopyFunction(defaults,thisEntity);
            //copies entity properties over defaults

        }
        else {
            //remove nonComponent property since we loop again later
            delete thisEntity.ignoreDefaults;
        }
    }
})() //end of entity instantiation

var npcComponents = {
    //all components should have public entityMap properties

    //No systems in use here. Just bundles of related attributes
    speedAttributes: new (function SpeedAttributes(){
        var shamblingBiped = {
            walkingAcceleration:1,
            topWalking:3
        },
        averageMan = {
            walkingAcceleration:3,
            runningAcceleration:4,
            topWalking: 4,
            topRunning: 6
        },
        programmer = {
            walkingAcceleration:1,
            runningAcceleration:100,
            topWalking:2
            topRunning:2000
        }; //end local/private vars

        //left is entity names | right is the component subcategory
        this.entityMap={
            zombie:shamblingBiped,
            lawyer:averageMan,
            nerd:programmer,
            gCostanza:programmer //makes a cameo during the fire-in-nursery stage
        }
    })(), //end speedAttributes

    //Now an example of an AI component - maps to function used to set eventHandlers
    //functions which, because JS is awesome we can pass around like candy
    //I'll just use some imaginary systems on this one

    aiFearful: new (function AiFearful(){
        var averageMan = Systems.AI({ //builds and returns eventSetting function
            fearThreshold:70, //%hitpoints remaining
            fleeFrom:'lastAttacker',
            tactic:'avoidIntercept',
            hazardAwareness:'distracted'
        }),
        programmer = Systems.AI({
            fearThreshold:95,
            fleeFrom:'anythingMoving',
            tactic:'beeline',
            hazardAwareness:'pantsCrappingPanic'
        });//end local vars/private members


         this.entityMap={
            lawyer:averageMan,
            nerd:averageMan, //nerds can run like programmers but are less cowardly
            gCostanza:programmer //makes a cameo during the fire-in-nursery stage
        }
    })(),//and more components...

    //Systems.AI is general and would get called for all the AI components.
    //It basically spits out functions used to set events on NPC objects that
    //determine their behavior. You could do it all in one shot but
    //the idea is to keep it granular enough for designers to actually tweak stuff
    //easily without tugging on developer pantlegs constantly.
    //e.g. SuperZombies, zombies, but slightly tougher, faster, smarter
}//end npcComponents

function createNPCConstructor(npcType){

    var components = npcEntities[npcType],

    //objConstructor is returned but components is still accessible via closure.

    objConstructor = function(){
        for(var x in components){
            //object iteration <property> in <object>

            var thisComponent = components[x];

            if(typeof thisComponent === 'function'){
                thisComponent.apply(this);
                //fires function as if it were a property of instance
                //would allow the function to add additional properties and set
                //event handlers via the 'this' keyword
            }
            else {
                objConstructor.prototype[x] = thisComponent;
                //public property accessed via reference to constructor prototype
                //good for low memory footprint among other things
            }
        }
    }
    return objConstructor;
}

var npcBuilders= {}; //empty object literal
for (var x in npcEntities){
    npcConstructors[x] = createNPCConstructor(x);
}

अब किसी भी समय आपको एनपीसी की आवश्यकता होती है, आप के साथ निर्माण कर सकते हैं npcBuilders.<npcName>();

एक GUI npcEntities और घटक वस्तुओं में प्लग कर सकता है और डिजाइनरों को पुरानी संस्थाओं को जोड़ने या बस मिश्रण और मेल घटकों द्वारा नई इकाइयां बनाने की अनुमति दे सकता है (हालांकि गैर-डिफ़ॉल्ट घटकों के लिए वहां कोई तंत्र नहीं है लेकिन विशेष घटकों को मक्खी में जोड़ा जा सकता है। जब तक इसके लिए एक परिभाषित घटक था तब तक कोड।


छह साल बाद इसे देखते हुए, मुझे यकीन नहीं है कि मैं अपना जवाब समझ सकता हूं। क्या इसमें सुधार किया जा सकता है?
एरिक रेपेन

1

मैंने उन लेखों में एंटिटी सिस्टम पर पढ़ा है जो लोगों को टिप्पणियों में प्रदान करते हैं, लेकिन मुझे अभी भी कुछ संदेह थे, इसलिए मैंने एक और प्रश्न पूछा ।

सबसे पहले, मेरी परिभाषा गलत थी। एंटिटीज और कंपोनेंट्स सिर्फ गूंगे डेटा होल्डर हैं, जबकि सिस्टम सभी फंक्शनलिटी प्रदान करते हैं।

मैंने अपने अधिकांश प्रश्न को यहाँ कवर करने के लिए पर्याप्त सीखा, इसलिए मैं इसका उत्तर दूंगा।

जिस Sceneवर्ग के बारे में मैं बात कर रहा था वह सिस्टम नहीं होना चाहिए। यह, हालांकि, एक केंद्रीय प्रबंधक होना चाहिए जो सभी संस्थाओं को पकड़ सकता है, संदेशों की सुविधा दे सकता है, और शायद सिस्टम का प्रबंधन भी कर सकता है। यह संस्थाओं के लिए एक प्रकार के कारखाने के रूप में भी कार्य कर सकता है, और मैंने इसे उसी तरह उपयोग करने का निर्णय लिया है। यह किसी भी प्रकार की इकाई ले सकता है , लेकिन तब उसे उस इकाई को एक उपयुक्त प्रणाली को खिलाना होगा (जो कि प्रदर्शन के कारणों के लिए, किसी भी प्रकार की जांच नहीं करनी चाहिए, जब तक कि वे बिटवाइस न हों)।

एडम को सुझाव देते हुए मुझे किसी ओओपी का उपयोग नहीं करना चाहिए, एडम का सुझाव है , लेकिन मुझे कोई कारण नहीं है कि दोनों संस्थाओं और घटकों के लिए ऑब्जेक्ट्स न हों, न कि केवल डंबल धारकों को।

Rendererबस एक प्रणाली के रूप में लागू किया जा सकता। यह ड्रॉबल ऑब्जेक्ट्स की एक सूची को बनाए रखेगा और draw()प्रत्येक 16ms में उनके रेंडर कंपोनेंट की विधि को कॉल करेगा ।


1
"एंटिटीज एंड कंपोनेंट्स सिर्फ गूंगा डेटा धारक होते हैं, जबकि सिस्टम सभी कार्यशीलता प्रदान करते हैं" "अपने रेंडर कंपोनेंट के ड्रॉ () विधि को कॉल करें" आप अभी भी भ्रमित हैं, इसके अलावा एक "ड्रॉ" विधि पूरी तरह से रेंडरिंग सिस्टम के पर्सपोज़ को हरा देती है। इसके अलावा, मुझे समझ में नहीं आता है कि आपका दृश्य ग्राफ़ रेंडरर का हिस्सा क्यों नहीं हो सकता है, यह सिर्फ एक सुविधाजनक उपकरण है, आप हमेशा नोड के रूप में अपने "ड्रॉबल" घटक को लागू कर सकते हैं। दृश्य ग्राफ को दृश्य से अधिक के लिए जिम्मेदार बनाना सिर्फ अनावश्यक है और मुझे यकीन है कि यह डिबग करने वाला है।
dreta

@dreta, रेंडरर वर्तमान में (इंजन का गैर-ईएस कार्यान्वयन) रूपांतरण, कैमरा परिवर्तन, अल्फा सामान करता है, और भविष्य में यह विभिन्न प्रभावों, जीयूआई और छाया को आकर्षित करेगा। उस सामान को समूह में रखना स्वाभाविक था। क्या स्टोरिंग संस्थाओं को बनाने के लिए दृश्य जिम्मेदार नहीं होना चाहिए? या कुछ और उन्हें स्टोर करना चाहिए? निर्माण भाग शायद उपयोगकर्ता द्वारा प्रदान किए गए घटकों को एक साथ एकत्रित करने की कुछ पंक्तियाँ हैं, यह वास्तव में "कुछ भी" पैदा नहीं कर रहा है, बस उदाहरण है।
जेकोरा

प्रत्येक वस्तु रेंडर नहीं होती है, न कि प्रत्येक ऑब्जेक्ट को टकराया जा सकता है या ध्वनि का उत्सर्जन किया जा सकता है, आपके सीन ऑब्जेक्ट के साथ आप चरम युग्मन कर रहे हैं, क्यों? यह सिर्फ लिखने और डीबग करने के लिए एक दर्द होने जा रहा है। संस्थाओं का उपयोग किसी वस्तु की पहचान करने के लिए किया जाता है, घटक डेटा को धारण करते हैं और सिस्टम डेटा पर काम करते हैं। आप रेंडरिंगसिस्टम और साउंडसिस्टम जैसी समुचित प्रणाली होने के बजाय सभी को एक साथ मैश करेंगे और यदि किसी इकाई में सभी आवश्यक घटक हैं तो केवल उन प्रणालियों को परेशान करें।
dreta

1
छाया कास्टिंग सामान्य रूप से प्रकाश स्रोतों से जुड़ी होती है, हालांकि आप बस एक घटक "कास्टशैडो" बना सकते हैं और गतिशील वस्तुओं को प्रदान करते समय इसे देख सकते हैं। यदि आप 2D कर रहे हैं तो यह केवल ऑर्डर करने का एक मूल मुद्दा है, एक साधारण चित्रकार का एल्गोरिथ्म आपके लिए इस मुद्दे को हल करेगा। टीबीएच आप बहुत जल्दी चिंता कर रहे हैं। जब आप इसे करने का समय लेंगे, तो आप इसका पता लगा लेंगे और आपके दिमाग में केवल वही है, अभी आप केवल खुद को भ्रमित कर रहे हैं। आप पहली बार में सब कुछ पाने की उम्मीद नहीं कर सकते, यह बस होने वाला नहीं है। जब आप इसे प्राप्त करेंगे तो आप उस पुल को पार कर लेंगे।
dreta

1
"एंटिटीज एंड कंपोनेंट्स सिर्फ गूंगा डेटा होल्डर हैं, जबकि सिस्टम सभी कार्यक्षमता प्रदान करते हैं।" जरुरी नहीं। वे कुछ लोगों के दृष्टिकोण में हैं। लेकिन दूसरों को नहीं। एकता इंजन को देखें - सभी व्यवहार घटकों में है।
काइलोटन

-2

निर्भरता प्रबंधन का परिचय 101।

यह कोर्स मानता है कि आपको निर्भरता इंजेक्शन और भंडार डिजाइन का बुनियादी ज्ञान है।

निर्भरता इंजेक्शन केवल वस्तुओं के लिए एक दूसरे से बात करने के लिए एक फैंसी तरीका है (संदेशों / संकेतों / प्रतिनिधियों / जो कुछ भी) के बिना सीधे युग्मित होने के बिना।

यह वाक्यांश द्वारा जाता है: " newगोंद है।"

मैं C # में इसका प्रदर्शन करूंगा।

public interface IEntity
{
    int[] Position { get; }
    int[] Size { get; }
    bool Update();
    void Render();
}

public interface IRenderSystem
{
    void Draw(IEntity entity);
}

public interface IMovementSystem
{
    bool CanMoveLeft();
    void MoveLeft();
    bool CanMoveRight();
    void MoveRight();
    bool CanMoveUp();
    void MoveUp();
    bool CanMoveDown();
    void MoveDown();
    bool Moved();
    int[] Position { get; set; }
}

public interface IInputSystem
{
    string Direction { get; set; }
}

public class Player : IEntity
{
    private readonly IInputSystem _inputSystem;
    private readonly IMovementSystem _movementSystem;
    private readonly IRenderSystem _renderSystem;
    private readonly int[] _size = new[] { 10, 10 };

    public Player(IRenderSystem renderSystem, IMovementSystem movementSystem, IInputSystem inputSystem)
    {
        _renderSystem = renderSystem;
        _movementSystem = movementSystem;
        _inputSystem = inputSystem;
    }

    public bool Update()
    {
        if (_inputSystem.Direction == "Left" && _movementSystem.CanMoveLeft())
            _movementSystem.MoveLeft();
        if (_inputSystem.Direction == "Right" && _movementSystem.CanMoveRight())
            _movementSystem.MoveRight();
        if (_inputSystem.Direction == "Up" && _movementSystem.CanMoveUp())
            _movementSystem.MoveUp();
        if (_inputSystem.Direction == "Down" && _movementSystem.CanMoveDown())
            _movementSystem.MoveDown();

        return _movementSystem.Moved();
    }

    public void Render()
    {
        if (_movementSystem.Moved())
            _renderSystem.Draw(this);
    }

    public int[] Position
    {
        get { return _movementSystem.Position; }
    }

    public int[] Size
    {
        get { return _size; }
    }
}

यह इनपुट, मूवमेंट और रेंडरिंग के लिए एक बुनियादी प्रणाली है। Playerवर्ग इस मामले में इकाई है और घटकों इंटरफेस है। Playerवर्ग कैसे एक ठोस के आंतरिक भागों के बारे में कुछ नहीं जानता IRenderSystem, IMovementSystemया IInputSystemकाम करते हैं। हालाँकि, Playerअंतरा परिणाम को कैसे पूरा किया जाता है, इसके आधार पर इंटरफेस सिग्नल भेजने का एक तरीका प्रदान करते हैं (उदाहरण के लिए IRenderSystem पर ड्रा करें)।

उदाहरण के लिए IMovementSystem के मेरे कार्यान्वयन को लें:

public interface IGameMap
{
    string LeftOf(int[] currentPosition);
    string RightOf(int[] currentPosition);
    string UpOf(int[] currentPosition);
    string DownOf(int[] currentPosition);
}

public class MovementSystem : IMovementSystem
{
    private readonly IGameMap _gameMap;
    private int[] _previousPosition;
    private readonly int[] _currentPosition;
    public MovementSystem(IGameMap gameMap, int[] initialPosition)
    {
        _gameMap = gameMap;
        _currentPosition = initialPosition;
        _previousPosition = initialPosition;
    }

    public bool CanMoveLeft()
    {
        return _gameMap.LeftOf(_currentPosition) == "Unoccupied";
    }

    public void MoveLeft()
    {
        _previousPosition = _currentPosition;
        _currentPosition[0]--;
    }

    public bool CanMoveRight()
    {
        return _gameMap.RightOf(_currentPosition) == "Unoccupied";
    }

    public void MoveRight()
    {
        _previousPosition = _currentPosition;
        _currentPosition[0]++;
    }

    public bool CanMoveUp()
    {
        return _gameMap.UpOf(_currentPosition) == "Unoccupied";
    }

    public void MoveUp()
    {
        _previousPosition = _currentPosition;
        _currentPosition[1]--;
    }

    public bool CanMoveDown()
    {
        return _gameMap.DownOf(_currentPosition) == "Unoccupied";
    }

    public void MoveDown()
    {
        _previousPosition = _currentPosition;
        _currentPosition[1]++;
    }

    public bool Moved()
    {
        return _previousPosition == _currentPosition;
    }

    public int[] Position
    {
        get { return _currentPosition; }
    }
}

MovementSystemअपनी निर्भरता हो सकती है और Playerदेखभाल भी नहीं होगी। इंटरफेस का उपयोग करके, एक गेम स्टेट मशीन बनाई जा सकती है:

public class GameEngine
{
    private readonly List<IEntity> _entities;
    private List<IEntity> _renderQueue; 

    public GameEngine()
    {
        _entities = new List<IEntity>();
    }

    public void RegisterEntity(IEntity entity)
    {
        _entities.Add(entity);
    }

    public void Update()
    {
        _renderQueue = new List<IEntity>();
        foreach (var entity in _entities)
        {
            if(entity.Update())
                _renderQueue.Add(entity);
        }
        // Linq version for those interested
        //_renderQueue.AddRange(_entities.Where(e => e.Update()));
    }

    public void Render()
    {
        foreach (var entity in _renderQueue)
        {
            entity.Render();
        }
    }
}

और यह एक सुंदर खेल की शुरुआत है (यह भी इकाई परीक्षण योग्य है)।

और कुछ परिवर्धन और कुछ बहुरूपता के साथ:

public interface IEntity
{
}

public interface IRenderableEntity : IEntity
{
    void Render();        
}

public interface IUpdateableEntity : IEntity
{
    void Update();
    bool Updated { get; }
}

public interface IRenderSystem
{
    void Draw(IRenderableEntity entity);
}

// new player class
public class Player : IRenderableEntity, IUpdateableEntity
{
    private readonly IInputSystem _inputSystem;
    private readonly IMovementSystem _movementSystem;
    private readonly IRenderSystem _renderSystem;
    private readonly int[] _size = new[] { 10, 10 };

    public Player(IRenderSystem renderSystem, IMovementSystem movementSystem, IInputSystem inputSystem)
    {
        _renderSystem = renderSystem;
        _movementSystem = movementSystem;
        _inputSystem = inputSystem;
    }

    public void Update()
    {
        if (_inputSystem.Direction == "Left" && _movementSystem.CanMoveLeft())
            _movementSystem.MoveLeft();
        if (_inputSystem.Direction == "Right" && _movementSystem.CanMoveRight())
            _movementSystem.MoveRight();
        if (_inputSystem.Direction == "Up" && _movementSystem.CanMoveUp())
            _movementSystem.MoveUp();
        if (_inputSystem.Direction == "Down" && _movementSystem.CanMoveDown())
            _movementSystem.MoveDown();
    }

    public bool Updated
    {
        get { return _movementSystem.Moved(); }
    }

    public void Render()
    {
        if (_movementSystem.Moved())
            _renderSystem.Draw(this);
    }

    public int[] Position
    {
        get { return _movementSystem.Position; }
    }

    public int[] Size
    {
        get { return _size; }
    }
}

public class GameEngine
{
    private readonly List<IEntity> _entities;
    private List<IRenderableEntity> _renderQueue; 

    public GameEngine()
    {
        _entities = new List<IEntity>();
    }

    public void RegisterEntity(IEntity entity)
    {
        _entities.Add(entity);
    }

    public void Update()
    {
        _renderQueue = new List<IRenderableEntity>();
        foreach (var entity in _entities)
        {
            if (entity is IUpdateableEntity)
            {
                var updateEntity = entity as IUpdateableEntity;
                updateEntity.Update();
            }

            if (entity is IRenderableEntity)
            {
                var renderEntity = entity as IRenderableEntity;
                _renderQueue.Add(renderEntity);
            }
        }
    }

    public void Render()
    {
        foreach (var entity in _renderQueue)
        {
            entity.Render();
        }
    }
}

अब हमारे पास एक प्राथमिक इकाई / घटक प्रणाली है जो कुलीन इंटरफेस और ढीली विरासत पर आधारित है।


1
यह घटक डिजाइन के खिलाफ है :) यदि आप एक खिलाड़ी को आवाज़ें और अन्य नहीं बनाना चाहते हैं तो आप क्या करेंगे?
काकीमारू

@Kikaimaru पास एक ISoundSystem में जो ध्वनि नहीं बजाता है। यानी कुछ नहीं करता।
डस्टिन किंगेन

3
-1, इसलिए नहीं कि यह खराब कोड है, लेकिन क्योंकि यह घटक-आधारित वास्तुकला के लिए बिल्कुल भी प्रासंगिक नहीं है - वास्तव में यह इस तरह के इंटरफेस का प्रसार है जिससे घटक बचने की कोशिश करते हैं।
काइलोटन

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