बाहरी घटक प्रबंधकों के साथ एक इकाई प्रणाली का आयोजन?


13

मैं एक टॉप-डाउन मल्टीप्लेयर 2D शूटर गेम के लिए एक गेम इंजन डिजाइन कर रहा हूं, जिसे मैं अन्य टॉप-डाउन शूटर गेम के लिए यथोचित पुन: उपयोग करना चाहता हूं। फिलहाल मैं सोच रहा हूं कि इसमें एंटिटी सिस्टम जैसा कुछ कैसे डिजाइन किया जाए। पहले मैंने इस बारे में सोचा:

मेरा एक वर्ग है जिसका नाम एंटिटी मैनजर है। इसे अपडेट नामक एक विधि को लागू करना चाहिए और ड्रा नामक एक अन्य। मेरे लिए तर्क और प्रतिपादन को अलग करने का कारण यह है कि तब मैं ड्रॉ विधि को छोड़ सकता हूं यदि एक स्टैंडअलोन सर्वर चल रहा है।

EntityManager का बेस बेसेंट की वस्तुओं की सूची है। प्रत्येक निकाय EntityModel (निकाय का प्राप्य प्रतिनिधित्व), EntityNetworkInterface और EntityPhysicalBody जैसे घटकों की एक सूची का मालिक है।

EntityManager भी EntityRenderManager, EntityNetworkManager और EntityPhysicsManager जैसे घटक प्रबंधकों की एक सूची का मालिक है। प्रत्येक घटक प्रबंधक इकाई घटकों के संदर्भ रखता है। इस कोड को संस्था की अपनी कक्षा से बाहर ले जाने के विभिन्न कारण हैं और इसके बजाय इसे सामूहिक रूप से करना है। उदाहरण के लिए, मैं खेल के लिए एक बाहरी भौतिकी पुस्तकालय, बॉक्स 2 डी का उपयोग कर रहा हूं। Box2D में, आप पहले निकायों और आकृतियों को एक दुनिया में जोड़ते हैं (इस मामले में EntityPhysicsManager के स्वामित्व में) और टक्कर कॉलबैक (जो कि मेरे सिस्टम में इकाई ऑब्जेक्ट के लिए भेजा जाएगा) को जोड़ते हैं। फिर आप एक फ़ंक्शन चलाते हैं जो सिस्टम में सब कुछ अनुकरण करता है। मुझे ऐसा करने के लिए बाहरी घटक प्रबंधक में ऐसा करने से बेहतर समाधान खोजना मुश्किल है।

इकाई निर्माण इस तरह से किया जाता है: EntityManager विधि RegisterEntity (unitClass, factory) को लागू करता है जो उस वर्ग की एक इकाई बनाने के लिए पंजीकृत करता है। यह विधि CreateEntity (unitClass) को भी लागू करता है, जो कि BaseEntity प्रकार की एक वस्तु लौटाएगा।

अब मेरी समस्या आती है: घटक के संदर्भ को घटक प्रबंधकों के लिए कैसे पंजीकृत किया जाएगा? मुझे नहीं पता कि मैं कारखाने / बंद से घटक प्रबंधकों का संदर्भ कैसे दूंगा।


मुझे नहीं पता कि शायद इसका मतलब एक हाइब्रिड सिस्टम है, लेकिन ऐसा लगता है कि आपके "मैनेजर" वही हैं जिन्हें मैंने आमतौर पर "सिस्टम" कहा है; यानी एंटिटी एक अमूर्त-आईडी है; एक घटक डेटा का एक पूल है; और जिसे आप "मैनेजर" कहते हैं, उसे आम तौर पर "सिस्टम" कहा जाता है। क्या मैं शब्दावली की सही व्याख्या कर रहा हूँ?
BRPocock

यहाँ मेरा सवाल दिलचस्पी का हो सकता है: खेल अवयव, खेल प्रबंधक और वस्तु गुण
जॉर्ज डकेट

Gamadu.com/artemis पर एक नज़र डालें और देखें कि क्या उनके तरीके आपके प्रश्न का उत्तर देते हैं।
पैट्रिक ह्यूजेस

1
इकाई प्रणाली को डिजाइन करने का कोई एक तरीका नहीं है क्योंकि इसकी परिभाषा पर बहुत कम सहमति है। @BRPocock क्या वर्णन करता है और यह भी कि आर्टीमिस किस संकोच का उपयोग करता है, इस ब्लॉग पर अधिक गहराई से वर्णित किया गया है: t-machine.org/index.php/category/entity-systems एक विकि के साथ: इकाई- sss.wikidot.com
user8363

जवाबों:


6

सिस्टम को कुछ प्रकार के मानचित्र, शब्दकोश वस्तु, या साहचर्य सरणी (भाषा के आधार पर) में घटक के लिए इकाई का एक महत्वपूर्ण मूल्य संग्रह करना चाहिए। इसके अलावा, जब आप अपना एंटिटी ऑब्जेक्ट बनाते हैं, तो मैं इसे एक प्रबंधक में संग्रहीत करने के बारे में चिंता नहीं करूंगा जब तक कि आपको किसी भी सिस्टम से इसे अपंजीकृत करने में सक्षम होने की आवश्यकता नहीं है। एक इकाई घटकों का एक सम्मिश्र है, लेकिन इसे किसी भी घटक अद्यतन को संभालना नहीं चाहिए। यह सिस्टम द्वारा नियंत्रित किया जाना चाहिए। इसके बजाय अपनी इकाई को एक ऐसी कुंजी के रूप में मानें जो सिस्टम में शामिल सभी घटकों के लिए मैप की गई है, साथ ही उन घटकों के लिए एक दूसरे से बात करने के लिए एक संचार केंद्र भी है।

एंटिटी-कंपोनेंट-सिस्टम मॉडल के बारे में बहुत बड़ी बात यह है कि आप किसी इकाई के बाकी घटकों के संदेशों को एक घटक से पास करने की क्षमता को काफी आसानी से लागू कर सकते हैं। यह एक घटक को वास्तव में यह जानने के बिना किसी अन्य घटक से बात करने की अनुमति देता है कि वह घटक कौन है या उसके द्वारा बदल रहे घटक को कैसे संभालना है। इसके बजाय यह एक संदेश पास करता है और घटक को स्वयं बदल देता है (यदि यह मौजूद है)

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

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

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

संक्षेप में:

इकाई घटकों की एक रचना है जो संदेश प्राप्त कर सकती है। इकाई संदेश प्राप्त कर सकते हैं, प्रतिनिधि ने कहा कि उनके सभी घटकों को अद्यतन करने के लिए संदेश। (स्थिति परिवर्तित संदेश, गति परिवर्तन दिशा, आदि) यह एक केंद्रीय मेलबॉक्स की तरह है जो सभी घटक एक दूसरे से सीधे बात करने के बजाय एक दूसरे से सुन सकते हैं।

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

सिस्टम एक निश्चित प्रकार के सभी घटकों का प्रबंधन करता है, और कहा जाता है कि प्रत्येक फ्रेम के घटकों को अद्यतन करने के लिए जिम्मेदार है, साथ ही घटक के संदेश भेजने के लिए वे उन इकाईयों का प्रबंधन करते हैं जो घटक से संबंधित हैं

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

उम्मीद है की यह मदद करेगा। यह एक डिज़ाइन पैटर्न का एक नरक है, लेकिन अगर सही किया जाए तो यह हास्यास्पद रूप से शक्तिशाली है।


0

मैं अपने इंजन में एक समान प्रणाली का उपयोग कर रहा हूं और जिस तरह से मैंने किया है वह प्रत्येक एंटिटी में अवयवों की एक सूची है। EntityManager से, मैं प्रत्येक इकाई को क्वेरी कर सकता हूँ और देख सकता हूँ कि उनमें से कौन से दिए गए घटक हैं। उदाहरण:

class Component
{
    private uint ID;
    // etc...
}

class Entity
{
    List<Component> Components;
    // etc...
    public bool Contains(Type type)
    {
        foreach(Component comp in Components)
        {
            if(typeof(comp) == type)
                return true;
        }
        return false;
    }
}

class EntityManager
{
    List<Entity> Entities;
    // etc...
    public List<Entity> GetEntitiesOfType(Type type)
    {
        List<Entity> results = new List<Entity>();
        foreach(Entity entity in Entities)
        {
            if(entity.Contains(type))
                results.Add(entity);
        }
        return results;
    }
}

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


3
कैविएट एम्प्टर: जिस बिंदु पर आपके एंटिटी में डेटा होता है, वह एक वस्तु है, एक इकाई नहीं ... इस संरचना में ईसीएस के सबसे अधिक लाभकारी (एसआईसी?) लाभों में से एक को खो देता है। "प्योर" E / C / S सिस्टम रिलेशनल हैं, ऑब्जेक्ट-ओरिएंटेड नहीं ... ऐसा नहीं है कि यह किसी केस (एस) के लिए जरूरी "बुरा" है, लेकिन यह निश्चित रूप से "रिलेशनल मॉडल को तोड़ रहा है"
BRPocock

2
मुझे यकीन नहीं है कि मैं आपको समझता हूं। मेरी समझ (और मुझे गलत होने पर कृपया सही करें) बुनियादी इकाई-घटक-प्रणाली में एक इकाई वर्ग होता है जिसमें घटक होते हैं और एक आईडी, नाम या कुछ पहचानकर्ता हो सकते हैं। मुझे लगता है कि इकाई के "प्रकार" से मेरा मतलब गलतफहमी हो सकता है। जब मैं इकाई "प्रकार" कहता हूं, तो मैं घटक के प्रकारों की बात कर रहा हूं। यह कहना है, एक इकाई एक "स्प्राइट" प्रकार है अगर इसमें स्प्राइट घटक होता है।
माइक क्लॅक

1
एक शुद्ध इकाई / घटक प्रणाली में, एक इकाई आमतौर पर परमाणु होती है: जैसे typedef long long int Entity; एक घटक एक रिकॉर्ड है (इसे एक ऑब्जेक्ट क्लास के रूप में लागू किया जा सकता है, या सिर्फ एक struct) जिसमें उस इकाई का संदर्भ है जिसमें यह संलग्न है; और एक प्रणाली एक विधि या विधियों का संग्रह होगा। ईसीएस मॉडल ओओपी मॉडल के साथ बहुत संगत नहीं है, हालांकि एक घटक (अधिकतर) डेटा-ओनली ऑब्जेक्ट हो सकता है, और एक सिस्टम एक कोड-केवल सिंगलटन ऑब्जेक्ट जिसका राज्य घटकों में रहता है ... हालांकि "हाइब्रिड" सिस्टम हैं "शुद्ध" लोगों की तुलना में अधिक आम है, वे जन्मजात लाभों में से कई खो देते हैं।
BRPocock

2
@BRPockock फिर से "शुद्ध" एंटिटी सिस्टम। मुझे लगता है कि एक वस्तु के रूप में एक इकाई पूरी तरह से ठीक है, यह एक साधारण आईडी नहीं है। एक बात क्रमबद्ध प्रतिनिधित्व है, एक वस्तु / एक अवधारणा / एक इकाई का दूसरा इन-मेमोरी लेआउट। जब तक आप डेटा-चालकता बनाए रख सकते हैं, तब तक किसी को गैर-मुहावरेदार कोड से नहीं जोड़ा जाना चाहिए क्योंकि यह "शुद्ध" तरीका है।
राइन

1
@ बीआरपॉक यह एक उचित चेतावनी है, लेकिन "टी-मशीन" जैसी इकाई प्रणालियों के लिए। मैं समझता हूं कि क्यों, लेकिन वे घटक-आधारित संस्थाओं को मॉडल करने के एकमात्र तरीके नहीं हैं। अभिनेता एक दिलचस्प विकल्प हैं। मैं विशेष रूप से विशुद्ध रूप से तार्किक संस्थाओं के लिए उनकी सराहना करता हूं।
राइन

0

1) आपका कारखाना तरीका EntityManager का एक संदर्भ होना चाहिए जिसने इसे बुलाया (मैं उदाहरण के रूप में C # का उपयोग करूँगा):

delegate BaseEntity EntityFactory(EntityManager manager);

2) क्या CreateEntity में भी एक id (उदाहरण के लिए एक स्ट्रिंग, पूर्णांक, यह आपके ऊपर है) वर्ग / प्रकार की इकाई के अलावा प्राप्त होता है, और स्वचालित रूप से उस आईडी का उपयोग करके एक कुंजी पर एक शब्दकोश में बनाई गई इकाई को पंजीकृत करता है:

class EntityManager
{
    // Rest of class omitted

    BaseEntity CreateEntity(string id, Type entityClass)
    {
        BaseEntity entity = factories[entityClass](this);
        registry.Add(id, entity);
        return entity;
    }

    Dictionary<Id, BaseEntity> registry;
}

3) आईडी द्वारा किसी भी संस्था को प्राप्त करने के लिए EntityManager के लिए एक योजक जोड़ें:

class EntityManager
{
    // Rest of class omitted

    BaseEntity GetEntity(string id)
    {
        return registry[id];
    }
}

और बस आपको अपने फैक्ट्री मेथड से किसी भी ComponentManager को रेफर करना होगा। उदाहरण के लिए:

BaseEntity CreateSomeSortOfEntity(EntityManager manager)
{
    // Create and configure entity
    BaseEntity entity = new BaseEntity();
    RenderComponent renderComponent = new RenderComponent();
    entity.AddComponent(renderComponent);

    // Get a reference to the render manager and register component
    RenderEntityManager renderer = manager.GetEntity("RenderEntityManager") as RenderEntityManager;
    if(renderer != null)
        renderer.Register(renderComponent)

    return entity;
}

Id के अलावा आप किसी प्रकार की संपत्ति (एक कस्टम एनम, या केवल भाषा के प्रकार सिस्टम पर निर्भर) का उपयोग कर सकते हैं, और एक ऐसा गेटर बना सकते हैं जो एक निश्चित प्रकार के सभी BaseEntities को लौटाता है।


1
पांडित्य नहीं, लेकिन फिर से ... एक शुद्ध इकाई (संबंधपरक) प्रणाली में, संस्थाओं के पास कोई प्रकार नहीं है, सिवाय इसके कि उनके घटकों के आधार पर उन्हें प्रदान किया जाए ...
BRPocock

@BRPocock: क्या आप एक उदाहरण बना सकते हैं जो शुद्ध गुण का अनुसरण करता है?
ज़ोलोमन

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

2
"शुद्ध" इकाई प्रणाली: रेफरी में इकाई आईडी को आम तौर पर कुछ इस तरह है: typedef unsigned long long int EntityID;; आदर्श यह है कि प्रत्येक सिस्टम एक अलग सीपीयू या होस्ट पर रह सकता है, और केवल उन घटकों को लाने की आवश्यकता होती है जो उस सिस्टम में प्रासंगिक / सक्रिय हैं। एंटिटी ऑब्जेक्ट के साथ, किसी को प्रत्येक होस्ट पर समान एंटिटी ऑब्जेक्ट को इंस्टेंट करना पड़ सकता है, जिससे स्केलिंग अधिक कठिन हो जाती है। एक शुद्ध इकाई-घटक-सिस्टम मॉडल आमतौर पर इकाई के बजाय सिस्टम द्वारा नोड्स (प्रक्रिया, सीपीयू या होस्ट) पर प्रसंस्करण को विभाजित करता है।
BRPocock

1
@DavidGouveia ने "अनुकूलन ... आईडी द्वारा संस्थाओं की तलाश" का उल्लेख किया। वास्तव में, (कुछ) सिस्टम मैंने इस तरह से लागू किया है, ऐसा नहीं करने के लिए करते हैं। अधिक बार, कुछ पैटर्न द्वारा घटकों का चयन करें जो यह दर्शाता है कि वे एक विशेष प्रणाली के लिए रुचि रखते हैं, केवल क्रॉस-घटक रूट्स के लिए एंटिटीज़ (आईडी) का उपयोग कर रहे हैं।
BRPocock
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.