घटक आधारित इकाई प्रणाली में संदेश हैंडलिंग को ठीक से कैसे लागू किया जाए?


30

मैं एक इकाई प्रणाली संस्करण लागू कर रहा हूं जिसमें:

  • एक इकाई जो एक आईडी से थोड़ा अधिक है जो घटकों को एक साथ बांधती है

  • घटक कक्षाओं का एक गुच्छा जिसमें "घटक तर्क" नहीं है, केवल डेटा है

  • सिस्टम कक्षाओं का एक गुच्छा (उर्फ "सबसिस्टम", "प्रबंधक")। ये सभी इकाई लॉजिक प्रोसेसिंग करते हैं। अधिकांश बुनियादी मामलों में, सिस्टम केवल उन संस्थाओं की सूची को गढ़ता है, जिनमें वे रुचि रखते हैं और उनमें से प्रत्येक पर एक कार्रवाई करते हैं

  • एक MessageChannel क्लास ऑब्जेक्ट जो सभी गेम सिस्टम द्वारा साझा किया जाता है। प्रत्येक प्रणाली को सुनने के लिए विशिष्ट प्रकार के संदेशों की सदस्यता ले सकते हैं और अन्य प्रणालियों को संदेश प्रसारित करने के लिए चैनल का उपयोग भी कर सकते हैं

सिस्टम संदेश हैंडलिंग का प्रारंभिक संस्करण कुछ इस तरह था:

  1. क्रमिक रूप से प्रत्येक गेम सिस्टम पर एक अद्यतन चलाएँ
  2. यदि कोई सिस्टम किसी कंपोनेंट के लिए कुछ करता है और वह एक्शन अन्य प्रणालियों के लिए रूचि का हो सकता है, तो सिस्टम एक उपयुक्त संदेश भेजता है (उदाहरण के लिए, सिस्टम कॉल

    messageChannel.Broadcast(new EntityMovedMessage(entity, oldPosition, newPosition))

    जब भी किसी इकाई को स्थानांतरित किया जाता है)

  3. प्रत्येक सिस्टम जो विशिष्ट संदेश के लिए सब्सक्राइब किया जाता है, उसे संदेश हैंडलिंग विधि कहा जाता है

  4. यदि कोई सिस्टम किसी ईवेंट को हैंडल कर रहा है, और ईवेंट प्रोसेसिंग लॉजिक को प्रसारित करने के लिए एक अन्य संदेश की आवश्यकता होती है, तो संदेश तुरंत प्रसारित हो जाता है और मैसेज प्रोसेसिंग विधियों की एक और श्रृंखला को कॉल किया जाता है

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

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

कुछ मामलों में यह एक समस्या का कारण बनता है क्योंकि सेल की सामग्री (सी # में इकाई वस्तुओं की एक सामान्य सूची) संशोधित हो जाती है, जबकि वे इससे अधिक पुनरावृत्त हो रहे हैं, इस प्रकार एक अपवाद को इट्रेटर द्वारा फेंक दिया जाता है।

तो ... मैं टकराव की जाँच के दौरान टकराव प्रणाली को बाधित होने से कैसे रोक सकता हूं?

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

मैंने क्या कोशिश की है:

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

संपादित करें - प्रश्नों के उत्तर, टिप्पणियाँ:

  • सेल की सामग्री को संशोधित करता है, जबकि टकराव प्रणाली उन पर पुनरावृत्ति करता है?

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

  • क्या आप एक वैश्विक आउटगोइंग संदेश कतार के साथ काम नहीं कर सकते?

मैंने हाल ही में एक वैश्विक कतार की कोशिश की। यह नई समस्याओं का कारण बनता है। समस्या: मैं एक टैंक इकाई को दीवार इकाई में स्थानांतरित करता हूं (टैंक कीबोर्ड के साथ नियंत्रित होता है)। फिर मैं टैंक की दिशा बदलने का फैसला करता हूं। टैंक और दीवार को प्रत्येक फ्रेम को अलग करने के लिए, CollidingRigidBodySeparationSystem टैंक को दीवार से सबसे छोटी राशि से दूर ले जाता है। जुदाई दिशा को टैंक की गति की दिशा के विपरीत होना चाहिए (जब खेल ड्राइंग शुरू होता है, तो टैंक को ऐसा दिखना चाहिए जैसे कि वह दीवार में कभी नहीं गया)। लेकिन दिशा नई दिशा के विपरीत हो जाती है, इस प्रकार टैंक को दीवार की तुलना में एक अलग तरफ स्थानांतरित करना शुरू में था। समस्या क्यों होती है: यह इस प्रकार है कि संदेश अब संभाला जाता है (सरलीकृत कोड):

public void Update(int deltaTime)
{   
    m_messageQueue.Enqueue(new TimePassedMessage(deltaTime));
    while (m_messageQueue.Count > 0)
    {
        Message message = m_messageQueue.Dequeue();
        this.Broadcast(message);
    }
}

private void Broadcast(Message message)
{       
    if (m_messageListenersByMessageType.ContainsKey(message.GetType()))
    {
        // NOTE: all IMessageListener objects here are systems.
        List<IMessageListener> messageListeners = m_messageListenersByMessageType[message.GetType()];
        foreach (IMessageListener listener in messageListeners)
        {
            listener.ReceiveMessage(message);
        }
    }
}

कोड इस तरह बहता है (मान लें कि यह पहला गेम फ्रेम नहीं है):

  1. सिस्टम TimePassedMessage को संसाधित करना प्रारंभ करता है
  2. InputHandingSystem कुंजी प्रेस को इकाई कार्रवाई में परिवर्तित करता है (इस मामले में, एक बाएं तीर MoveWest कार्रवाई में बदल जाता है)। एक्शन एक्सिक्यूटर घटक में एंटिटी एक्शन संग्रहीत है
  3. ActionExecutionSystem , निकाय कार्रवाई की प्रतिक्रिया में, एक मूवमेंट जोड़ता है DirectChangeRequestedMessage संदेश कतार के अंत में
  4. MovementSystem वेलोसिटी घटक डेटा के आधार पर इकाई स्थिति को स्थानांतरित करता है और कतार के अंत में स्थिति-परिवर्तनशील संदेश जोड़ता है। आंदोलन पिछले फ्रेम के आंदोलन की दिशा / वेग का उपयोग करके किया जाता है (चलो उत्तर कहते हैं)
  5. सिस्टम TimePassedMessage को संसाधित करना बंद कर देता है
  6. सिस्टम मूवमेंट शुरू करते हैं MoveDDirectionChangeRequestedMessage
  7. मूवमेंट सिस्टम अनुरोध के अनुसार इकाई वेग / चालन दिशा बदलता है
  8. सिस्टम मूवमेंट को रोकते हैं MoveDDirectionChangeRequestedMessage
  9. सिस्टम स्थिति निर्धारण की प्रक्रिया शुरू करते हैं
  10. CollisionDetectionSystem का पता चलता है कि क्योंकि एक इकाई चली गई, यह दूसरी इकाई में चला गया (टैंक एक दीवार के अंदर चला गया)। यह कतार में एक CollisionOccuredMessage जोड़ता है
  11. सिस्टम पॉजिशन को बंद कर देता है
  12. सिस्टम CollisionOccuredMessage को प्रोसेस करना शुरू करते हैं
  13. CollidingRigidBodySeparationSystem टैंक और दीवार को अलग करके टकराव की प्रतिक्रिया करता है। चूंकि दीवार स्थिर है, केवल टैंक को स्थानांतरित किया गया है। टैंकों की आवाजाही दिशा का उपयोग एक संकेतक के रूप में किया जाता है कि टंकी कहाँ से आई है। यह एक विपरीत दिशा में ऑफसेट है

बग: जब टैंक ने इस फ्रेम को स्थानांतरित किया, तो यह पिछले फ्रेम से आंदोलन की दिशा का उपयोग कर गया, लेकिन जब इसे अलग किया जा रहा था, तो THIS फ्रेम से आंदोलन की दिशा का उपयोग किया गया था, भले ही यह पहले से ही अलग था। यह काम नहीं करना चाहिए!

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

  • आप Gamadu.com/artemis को पढ़ना चाह सकते हैं, यह देखने के लिए कि उन्होंने पहलू के साथ क्या किया है, जो आपके द्वारा देखी जा रही समस्याओं में से कुछ को चरणबद्ध करता है।

दरअसल, मैं आर्टेमिस से काफी समय से परिचित हूं। जांच की गई कि यह स्रोत कोड है, मंचों को पढ़ें, लेकिन मैंने "पहलू" को केवल कुछ ही स्थानों पर उल्लिखित किया है और, जहां तक ​​मैं इसे समझता हूं, उनका मूल रूप से "सिस्टम" है। लेकिन मैं यह नहीं देख सकता कि आर्टेमिस ने मेरी कुछ समस्याओं को कैसे हल किया। यह संदेशों का उपयोग भी नहीं करता है।

  • इसे भी देखें: "इकाई संचार: संदेश कतार बनाम प्रकाशन / सदस्यता लें सिग्नल / स्लॉट्स"

मैं पहले से ही सभी gamedev.stackexchange प्रश्नों को इकाई सिस्टम के बारे में पढ़ चुका हूँ। यह उन समस्याओं पर चर्चा नहीं करता है जो मैं सामना कर रहा हूं। क्या मैं कुछ भूल रहा हूँ?

  • दो मामलों को अलग-अलग तरीके से हैंडल करें, ग्रिड को अपडेट करना आंदोलन के संदेशों पर भरोसा करने की आवश्यकता नहीं है क्योंकि यह टकराव प्रणाली का हिस्सा है

मुझे नहीं पता तुम्हारा क्या मतलब है। CollisionDetectionSystem के पुराने कार्यान्वयन सिर्फ एक अपडेट पर टकरावों की जांच करेंगे (जब एक TimePassedMessage हैंडल किया गया था), लेकिन मुझे प्रदर्शन के कारण जितना हो सके चेक को कम करना पड़ा। इसलिए जब एक इकाई चलती है (मेरे खेल में अधिकांश इकाइयाँ स्थिर होती हैं) तो मैंने टक्कर की जाँच पर स्विच किया।


ऐसा कुछ है जो मेरे लिए स्पष्ट नहीं है। सेल की सामग्री को संशोधित करता है, जबकि टकराव प्रणाली उन पर पुनरावृत्ति करता है?
पॉल मंटा

क्या आप एक वैश्विक आउटगोइंग संदेश कतार के साथ काम नहीं कर सकते? इसलिए सभी संदेश हर बार किसी सिस्टम के हो जाने के बाद भेजे जाते हैं, इसमें सिस्टम सेल्फ डिस्ट्रक्टिंग भी शामिल है।
रॉय टी।

अगर आप इस कंफर्टेबल डिज़ाइन को रखना चाहते हैं तो आपको @RoyT को फॉलो करना होगा। आपकी अनुक्रमण समस्या को संभालने के लिए यह एकमात्र तरीका है (बिना जटिल, समय आधारित संदेश के)। आप यह देखने के लिए कि वे क्या कर रहे हैं पहलू को देखने के लिए gamadu.com/artemis पढ़ना चाहते हैं , जो आपके द्वारा देखी जा रही समस्याओं में से कुछ को चरणबद्ध करता है।
पैट्रिक ह्यूजेस


2
आप सीखना चाह सकते हैं कि Axum ने CTP को डाउनलोड करके और कुछ कोड संकलित करके कैसे किया - और फिर ILSpy का उपयोग करके C # के परिणाम को उल्टा कर दिया। संदेश पास करना अभिनेता मॉडल भाषाओं की एक महत्वपूर्ण विशेषता है और मुझे यकीन है कि माइक्रोसॉफ्ट जानता है कि वे क्या कर रहे हैं - इसलिए आप पा सकते हैं कि उनके पास 'सर्वश्रेष्ठ' कार्यान्वयन था।
जोनाथन डिकिंसन

जवाबों:


12

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

जैसा कि मैंने आपके प्रश्न के शब्दों को समझा है, आपकी टक्कर प्रणाली को अपडेट करने का आपका तरीका वर्तमान में मोटे तौर पर निम्नलिखित की तरह दिखता है।

for each possible collision
    check for collision
    handle collision
    modify collision world to reflect change // exception happens here

इस तरह से स्पष्ट रूप से लिखा गया है, आप देख सकते हैं कि आपके लूप की तीन जिम्मेदारियां हैं, जब इसे केवल एक होना चाहिए। अपनी समस्या को हल करने के लिए, अपने वर्तमान लूप को तीन अलग-अलग छोरों में विभाजित करें जो तीन अलग-अलग एल्गोरिदम पास का प्रतिनिधित्व करते हैं ।

for each possible collision
    check for collision, record it if a collision occurs

for each found collision
    handle collision, record the collision response (delete object, ignore, etc.)

for each collision response
    modify collision world according to response

अपने मूल लूप को तीन सब्लूप में विभाजित करके, अब आप कभी भी उस संग्रह को संशोधित करने का प्रयास नहीं करते हैं जिस पर आप वर्तमान में पुनरावृत्त हो रहे हैं। यह भी ध्यान दें कि आप अपने मूल लूप की तुलना में अधिक काम नहीं कर रहे हैं, और वास्तव में आप क्रमिक रूप से कई बार एक ही संचालन करके कुछ कैश जीत हासिल कर सकते हैं।

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


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

11

घटक आधारित इकाई प्रणाली में संदेश हैंडलिंग को ठीक से कैसे लागू किया जाए?

मैं कहूंगा कि आप दो प्रकार के संदेश चाहते हैं: सिंक्रोनस और एसिंकोनस। सिंक्रोनस संदेशों को तुरंत संभाला जाता है जबकि एसिंक्रोनस को एक ही स्टैक फ्रेम में नहीं संभाला जाता है (लेकिन उसी गेम फ्रेम में हैंडल किया जा सकता है)। निर्णय जो कि आमतौर पर "प्रति संदेश वर्ग" आधार पर किया जाता है, उदाहरण के लिए "सभी शत्रुतापूर्ण संदेश अतुल्यकालिक हैं"।

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

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

आपने पहले से ही सिंक्रोनस-ओनली मैसेज सिस्टम के साथ एक और सामान्य समस्या का उल्लेख किया है: सिंक्रोनस मैसेज सिस्टम के साथ मेरे अनुभव के अनुसार, इन सूचियों के दौरान पुनरावृत्ति करते समय सामान्य रूप से त्रुटियों और दु: खों के सबसे अधिक मामलों में से एक है।

इसके बारे में सोचें: यह सिंक्रोनस की प्रकृति में है (तुरंत कुछ कार्रवाई के सभी प्रभाव के बाद) और संदेश प्रणाली (प्रेषक से रिसीवर को हटाना ) ताकि प्रेषक को यह पता न चले कि कौन क्रिया पर प्रतिक्रिया दे रहा है) जिसे आप आसानी से नहीं कर पाएंगे ऐसे लूप स्पॉट करें। मैं जो कह रहा हूं वह है: इस तरह के स्व-संशोधित पुनरावृत्ति को संभालने के लिए तैयार रहें। इसके थोड़े "डिजाइन द्वारा"। ;-)

मैं टकराव प्रणाली को बाधित होने से कैसे रोक सकता हूं जबकि यह टक्करों की जांच करता है?

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

समस्या: यदि सिस्टम A, सिस्टम B की कतार में एक संदेश जोड़ता है, तो यह अच्छी तरह से काम करता है यदि सिस्टम B सिस्टम A (बाद में उसी गेम फ़्रेम) से अपडेट किया जाए; अन्यथा यह अगले गेम फ्रेम को संसाधित करने के लिए संदेश का कारण बनता है (कुछ प्रणालियों के लिए वांछनीय नहीं)

आसान:

जबकि (कतार (खाली) ()) {कतार.पॉप ()। संभाल (); }

बस जब तक कोई संदेश नहीं रहता तब तक कतार को बार-बार चलाएं। (यदि आप अब "अंतहीन लूप" चिल्लाते हैं, तो याद रखें कि आपको शायद यह समस्या "संदेश स्पैमिंग" के रूप में होगी यदि यह अगले फ्रेम में देरी होगी। आप अंतहीन छोरों का पता लगाने के लिए पुनरावृत्तियों की एक बड़ी संख्या के लिए जोर दे सकते हैं। अगर आपको ऐसा लगता है;))


ध्यान दें कि मैंने एसिंक्रोनस संदेशों को हैंडल करने पर "बिल्कुल" के बारे में बात नहीं की। मेरी राय में, यह पूरी तरह से ठीक है कि टकराव का पता लगाने वाले मॉड्यूल को खत्म होने के बाद अपने संदेशों को फ्लश करने की अनुमति दी जाए। आप इसे "तुल्यकालिक संदेश, लूप के अंत तक विलंबित" या "बस इसे पुनरावृत्ति करते समय संशोधित किया जा सकता है कि इस तरह से लागू करने के कुछ निफ्टी" के रूप में सोच सकते हैं
इमी

5

यदि आप वास्तव में ईसीएस के डेटा-उन्मुख-डिज़ाइन प्रकृति का उपयोग करने की कोशिश कर रहे हैं, तो आप ऐसा करने के सबसे डीओडी तरीके के बारे में सोचना चाह सकते हैं।

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

उदाहरण के लिए, CollisionSystem टकराव की घटनाओं से भरा एक बफर उत्पन्न करेगा। टक्कर के बाद चलने वाली कोई अन्य प्रणाली फिर सूची के माध्यम से पुनरावृति कर सकती है और आवश्यकतानुसार प्रक्रिया कर सकती है।

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

यदि आप प्रत्येक सिस्टम में लगातार ऑर्डर किए गए कंपोनेंट्स रखते हैं (जैसे कि एंटिटी आईडी या उसके जैसे सभी कंपोनेंट्स ऑर्डर करते हैं) तो आपको यह भी अच्छा फायदा मिलेगा कि मैसेज उनके ऊपर चलने और संबंधित कंपोनेंट देखने के लिए सबसे कुशल ऑर्डर में उत्पन्न होंगे प्रसंस्करण प्रणाली। यही है, यदि आपके पास 1, 2, और 3 इकाइयाँ हैं, तो उस क्रम में संदेश उत्पन्न होते हैं और संदेश को संसाधित करते समय किए गए घटक लुकअप पते के क्रम में सख्ती से बढ़ते हुए (जो कि सबसे तेज़ है) होगा।


1
+1, लेकिन मैं यह नहीं मान सकता कि इस दृष्टिकोण का कोई नुकसान नहीं है। क्या यह हमें सिस्टम के बीच अन्योन्याश्रितता के लिए बाध्य नहीं करता है? या हो सकता है कि ये अन्योन्याश्रितियाँ एक तरह से या किसी अन्य तरह से हार्डकोडेड हों?
पैट्रीक कज़ाचर्सकी

2
@ डेडलस: अगर गेम लॉजिक को सही लॉजिक करने के लिए फिजिक्स अपडेट की जरूरत है, तो आप उस निर्भरता के लिए कैसे नहीं होंगे ? यहां तक ​​कि एक पबसुब मॉडल के साथ, आपको स्पष्ट रूप से इस तरह के और इस तरह के संदेश प्रकार की सदस्यता लेनी होगी जो केवल किसी अन्य सिस्टम द्वारा उत्पन्न होता है। निर्भरता से बचना कठिन है, और ज्यादातर सही परतों का पता लगाना है। उदाहरण के लिए, ग्राफिक्स और भौतिकी स्वतंत्र हैं, लेकिन एक उच्च स्तरीय गोंद परत होगी जो सुनिश्चित करती है कि प्रक्षेपित भौतिकी सिमुलेशन अपडेट ग्राफिक्स आदि में परिलक्षित होते हैं
शॉन मिडिलिचच

यह स्वीकृत उत्तर होना चाहिए। इस बारे में जाने का एक सरल तरीका बस एक नए प्रकार का घटक बनाना है, उदाहरण के लिए CollisionResolvable जो टकराव के बाद चीजों को करने में रुचि रखने वाले हर सिस्टम द्वारा संसाधित हो जाएगा। जो ड्रेक के प्रस्ताव के साथ अच्छी तरह से फिट होगा, हालांकि हर उपखंड लूप के लिए एक प्रणाली है।
user8363
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.