क्या एक घटना प्रणाली स्थापित करने का एक बेहतर तरीका है?


9

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

वर्तमान में मेरे पास दो विधियाँ हैं:

  1. सबसे सरल: सभी वस्तुओं को एक वेक्टर में जोड़ा जाता है जब किसी घटना को भेजा जाता है तो सभी वस्तुओं को ईवेंट हैंडल के माध्यम से भेजा जाता है।

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

ये पहली विधि बहुत सी वस्तुओं के लिए काफी धीमी (स्पष्ट रूप से) है, लेकिन बहुत कम वस्तुओं के लिए काफी त्वरित है। जबकि दूसरी विधि बड़ी वस्तुओं के साथ काफी तेज है जो विभिन्न प्रकार की घटनाओं को संभालना चाहते हैं, लेकिन एक ही प्रकार की घटना को संभालने वाली वस्तुओं के साथ प्रति वस्तु की तुलना में पहली विधि की तुलना में धीमी है।

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


1
यह हैश मैप्स (या हैश टेबल) के लिए किस तरह का है, स्ट्रिंग को हैश नंबर तक गणना की जाती है, जिसका उपयोग किसी सरणी में सीधे देखने के लिए किया जाता है। en.wikipedia.org/wiki/Hash_table
पैट्रिक ह्यूजेस

एक अच्छा सवाल है: क्या यह वास्तव में एक प्रदर्शन अड़चन है, या आप सिर्फ समय से पहले चिंता कर रहे हैं?
जरी कोमप्पा

यह पहले से ही लागू है, और एक अड़चन है, जब कई वस्तुओं का उपयोग किया जाता है। अड़चन की कमी के बारे में मेरी पिछली टिप्पणी आवेदन में ही नहीं थी, बल्कि वास्तव में ऊपर के दो कार्यान्वयनों के बीच गति का अंतर था जहां समान संख्या में वस्तुओं को वास्तव में संभाला गया था। मैं ईवेंट सिस्टम बनाने के अन्य तरीकों की उम्मीद कर रहा था ... हालाँकि इस थ्रेड के कुछ विचार काफी गति बढ़ाएंगे, विशेष रूप से ईवेंट सिस्टम को लोड करने में (11-25 पूर्ण सेकंड लोड समय 100000 ऑब्जेक्ट्स के साथ)
अल्टिफिनिटस

100K वस्तुओं सिर्फ एक खेल के लिए भयानक लगता है। क्या यह सर्वर या अंतिम उपयोगकर्ता क्लाइंट अनुप्रयोग है?
पैट्रिक ह्यूजेस

यह मेरा इंजन है, इसलिए मैं वास्तव में लचीलेपन के लिए जा रहा हूं। यह सर्वर अनुप्रयोगों और अंतिम उपयोगकर्ता अनुप्रयोगों (कम अक्सर पहले, अनुकूलन) में उपयोग किया जाएगा
अल्टीमेटिनिट्स

जवाबों:


5

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

यदि वस्तुओं को अक्सर बनाया और नष्ट किया जा रहा है, तो वस्तुओं के वैक्टर में बहुत अधिक मंथन हो सकता है। इस मामले में आप वैक्टर के बजाय लिंक की गई सूचियों का उपयोग करके लाभ उठा सकते हैं; वे प्रविष्टि और विलोपन के लिए तेज़ हैं।


अड़चन बड़ी नहीं है (100,000 वस्तुओं के लिए यह खो जाती है ।0000076 एमएस / ऑब्जेक्ट) लेकिन मुझे लगता है कि आपका विचार एक महान विचार है! मुझे लगता है कि मैं वास्तव में आईडी की एक बार खोज करूंगा, और ईवेंटआईडी को मूल स्ट्रिंग डेटा के बजाय एक इंट के रूप में संग्रहीत किया है। और मैं वास्तव में जुड़े सूचियों, अच्छा विचार के बारे में सोचा नहीं था।
अल्टिफिनिटस

1
+1 आईडी को प्रीप्रोसेस करने के लिए। आप यह भी एक EventType प्रकार है कि प्रत्येक मॉड्यूल कुछ के माध्यम से प्राप्त कर सकते हैं होने के द्वारा यह आलसी कर सकता है EventType takeDamageEvent = EventSystem::CacheEventType("takeDamageEvent");। इसे कक्षाओं का एक स्थिर सदस्य बनाएं और आपके पास प्रत्येक कक्षा में केवल एक ही कॉपी होगी जो इसकी आवश्यकता है।
michael.bartnett

2
ध्यान दें कि स्ट्रिंग्स के बजाय आईडी स्टोर करना डिबगिंग को कुछ मुश्किल बना देगा। यह हमेशा उपयोगी होता है कि कुछ पाठ निर्दिष्ट करते हुए देखें कि कोई वस्तु कहां से आई है। आप आईडी और स्ट्रिंग दोनों को संग्रहीत करके आधे रास्ते पर जा सकते हैं, जिसे आप डिबगिंग उद्देश्यों के लिए रखते हैं (शायद रिलीज़ बिल्ड में भी हटा दिया गया है)।
निकोल बोलस

2

ठीक है, चलो पहले सामान को बाहर निकालें। आपके पास mapस्ट्रिंग्स (ईवेंट का नाम, संभवतः) और पूर्णांकों (पंजीकृत ईवेंट श्रोताओं का सूचकांक) के बीच यह है।

लुकअप समय mapदो चीजों पर आधारित है: मानचित्र में वस्तुओं की संख्या, और दो कुंजी (कैश मुद्दों की अनदेखी) के बीच तुलना करने में लगने वाला समय। यदि लुकअप समय एक समस्या है, तो इसे हैंडल करने का एक तरीका स्ट्रिंग प्रकार को बदलकर तुलना फ़ंक्शन को बदलना है।

मान लें कि आप उपयोग कर रहे हैं std::stringऔर operator<तुलना के लिए। यह अत्यधिक अक्षम है; यह एक बाइट-वार तुलना करता है। आप असली स्ट्रिंग की तुलना में कम परवाह नहीं करते हैं; आपको बस किसी प्रकार की तुलना की आवश्यकता है जो एक सख्त-कमजोर आदेश देता है (क्योंकि mapअन्यथा काम नहीं करता है)।

तो आपको इसके बजाय 32-बाइट वाली निश्चित लंबाई वाली स्ट्रिंग का उपयोग करना चाहिए std::string। मैं इनका उपयोग पहचानकर्ताओं के लिए करता हूं। इन निश्चित तारों के लिए तुलना परीक्षण बाइट-वार तुलना नहीं करते हैं; वे इसके बजाय 32-बिट (या 64-बिट) तुलना करते हैं। यह प्रत्येक 4 बाइट्स को एक अहस्ताक्षरित पूर्णांक के रूप में लेता है और अन्य स्ट्रिंग के संबंधित 4 बाइट्स के साथ इसकी तुलना करता है। इस तरह, तुलना केवल 8 की तुलना में अधिक होती है। यह एक सख्त-कमजोर ऑर्डरिंग सुनिश्चित करता है, हालांकि ऑर्डरिंग का चरित्र के रूप में डेटा से कोई लेना-देना नहीं है।

31 बाइट्स (NULL वर्ण की आवश्यकता) से अधिक लंबे समय तक तार संकरा होता है (लेकिन बीच में से, बल्कि सिरों को काटता है। मुझे लगता है कि एन्ट्रापी शुरुआत और अंत में सबसे बड़ा हो जाता है)। और उस पैड की तुलना में छोटे तार शेष पात्रों के साथ बाहर \0

अब, आप mapपूरी तरह से खाई और एक हैश तालिका का उपयोग कर सकते हैं । यदि आपके पास वास्तव में 100,000 से अधिक विभिन्न प्रकार के इवेंट प्रकार हैं, तो यह एक अच्छा विचार हो सकता है। लेकिन मैं एक ऐसे खेल के बारे में नहीं जानता जहाँ यह एक उचित उचित बात होगी।


इसलिए आपको std :: string की बजाय 32-बाइट की निर्धारित लंबाई वाली स्ट्रिंग का उपयोग करना चाहिए। बहुत खुबस! मैंने स्ट्रिंग प्रकार को बदलने के लिए नहीं सोचा था।
अल्टिफिनिटस

0

सामान्य प्रश्न का उत्तर देने के लिए:

इवेंट सिस्टम को सेट करने का बेहतर तरीका

वहां कोई नहीं है। आप केवल अपने इवेंट सिस्टम के लिए आपके पास मौजूद विशिष्ट आवश्यकताओं की पहचान कर सकते हैं (कई अलग-अलग हो सकते हैं) और फिर सही काम के लिए सही उपकरण का उपयोग करें।

मैंने इवेंट सिस्टम के टन को सामान्य करने का प्रयास किया है और मैं इस निष्कर्ष पर पहुंचा हूं। क्योंकि ट्रेडऑफ़ वास्तव में भिन्न होते हैं यदि आप इसे संकलन-समय या रन-टाइम बनाते हैं, यदि आप ऑब्जेक्ट पदानुक्रम या ब्लैकबोर्ड आदि का उपयोग करते हैं।

सबसे अच्छा तरीका विभिन्न प्रकार के इवेंट सिस्टम का अध्ययन करना है और फिर आपके पास सुराग होगा कि किस मामले में उपयोग करना है।

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

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