इवेंट मैनेजर सिस्टम डिज़ाइन करते समय मुझे क्या विचार करना चाहिए?


9

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

मुझे पता है, सिद्धांत रूप में , एक इवेंट मैनेजर को क्या करना चाहिए: वस्तुओं को कुछ घटनाओं के लिए "रजिस्टर" करने की अनुमति दें, और जब भी इवेंट मैनेजर को किसी घटना की सूचना मिलती है, तो इवेंट को "पंजीकृत" श्रोताओं को प्रसारित करें। मैं क्या कर रहा हूँ इस पर अमल करना शुरू कर दिया है।

मैं खरोंच से एक घटना प्रणाली को लागू करने के बारे में ऑनलाइन, कुछ भी नहीं पा रहा हूं, इसलिए मैं इस मामले में सबसे अच्छे अभ्यासों के बारे में इनपुट की तलाश कर रहा हूं - मुझे क्या करना चाहिए और क्या नहीं करना चाहिए

उदाहरण के लिए, क्या वास्तव में मेरे खेल की प्रत्येक वस्तु के लिए एक EventManagerक्षेत्र होना आवश्यक है? चूंकि मेरे सभी गेम ऑब्जेक्ट्स को एक सिंगल, एब्स्ट्रैक्ट पैरेंट क्लास से विरासत में मिला है, मुझे लगता है कि मुझे एक स्टेटिक रेफरेंस का उपयोग करने में सक्षम होना चाहिए, ताकि सभी गेम ऑब्जेक्ट्स के बीच साझा किए गए इवेंट मैनेजर का केवल एक उदाहरण हो। मैं एप्लेट के साथ ऐसा ही कुछ करता हूं, जिसका उपयोग मैं प्रत्येक वस्तु को पहले से ही प्रस्तुत करने के लिए करता हूं।

मुझे लगता है कि मुझे प्रत्येक संभावित सब्सक्राइब्ड ईवेंट के लिए कुछ प्रकार के संग्रह को बनाए रखना होगा - आवश्यकतानुसार गेम ऑब्जेक्ट्स को सूची से जोड़ना और निकालना। मुझे लगता है कि उन घटनाओं की एक कतार बनाना संभव होना चाहिए जिन्हें प्रसारित करने की आवश्यकता है, जिस स्थिति में मैं मुख्य गेम लूप में "EventManager.Update ()" जोड़ सकता हूं, और इस Update()पद्धति को अंत में होने वाली घटनाओं को प्रसारित कर सकता हूं प्रत्येक फ्रेम के। अंत में, प्रत्येक वस्तु के पास एक HandleEvent(Event e)विधि होगी, ताकि वे उचित रूप से पार्स और प्रतिक्रिया कर सकें।


क्या इस तरह की प्रणाली को लागू करने की दिशा में यह ध्वनि उचित है, या क्या मैं रास्ते से हट गया हूं और / या कुछ स्पष्ट याद कर रहा हूं?


2
gamedev.stackexchange.com/questions/7718/… यह पूर्व में दिया गया एक क्यू / एआई है जो आपको आरंभ करने में मदद कर सकता है।
जेम्स

@ जेम्स अह - एक अच्छी कड़ी की तरह दिखता है। धन्यवाद! मुझे लगता है कि मैं इससे पहले चूक गया था।
रेवेन ड्रीमर

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

जवाबों:


6

यह जितना चाहें उतना सरल हो सकता है।

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

कोशिश मत करो और बाहर काम करो कि एक इवेंट मैनेजर को क्या करना चाहिए - वह काम करो जो आपको करने की आवश्यकता है। बाकी को वहां से या कम से कम कुछ और विशिष्ट प्रश्नों का सुझाव देना चाहिए।


3
+1 के लिए "कोशिश मत करो और एक एक्स 'क्या करना चाहिए - क्या बाहर काम करने के लिए आपको इसकी आवश्यकता है।" वास्तव में, इवेंट मैनेजर को तब तक न जोड़ें जब तक आपको ऐसा महसूस न हो कि आपको फ़ंक्शंस को कॉल करने के लिए कुछ decoupled-yet-centralized तरीका चाहिए।

@JoeWreschnig ओह गॉड यस =) "वर्क आउट जो आपको इसे करने की आवश्यकता है" यह सलाह के शीर्ष 3 बिट्स में से है जिसे किसी भी डेवलपर को ध्यान में रखना चाहिए।
पैट्रिक ह्यूजेस

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

3

एक इवेंट सिस्टम की तीन आवश्यक विधियाँ एक addListener () मेथड, एक RemoveListener () मेथड, और एक विधि प्रेषण है ()। अर्थात्, एक विधि ऑब्जेक्ट किसी घटना के लिए रजिस्टर करने के लिए उपयोग करती है, एक विधि ऑब्जेक्ट्स अन-रजिस्टर करने के लिए उपयोग करती है, और एक विधि वास्तव में सभी श्रोताओं के लिए एक घटना प्रसारित करती है। बाकी सब कुछ ग्रेवी है।

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

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

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

उदाहरण के लिए, क्या मेरे GameObjects में से प्रत्येक के लिए "EventManagner" फ़ील्ड होना आवश्यक है? चूंकि मेरे सभी गेमऑब्जेक्ट्स एक एकल, अमूर्त अभिभावक वर्ग से प्राप्त होते हैं, मुझे लगता है कि मुझे एक स्थिर संदर्भ का उपयोग करने में सक्षम होना चाहिए, ताकि सभी गेम ऑब्जेक्ट्स के बीच साझा किए गए EventManager का केवल एक उदाहरण हो।

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


हाँ, मैं पहली बार वास्तव में समझा और कार्यान्वित निर्भरता इंजेक्शन एक EventDispatcher वस्तु के लिए था। एक बार जब मुझे लगा कि मेरी बेल्ट के नीचे, मुझे उस पैटर्न के साथ बहुत सारे सामान को रिफैक्टर करने के लिए खुजली हो रही है।
jhocking

0

अस्वीकरण

Im एक जावा प्रोग्रामर नहीं है, लेकिन मैंने एक लेख लिखा है जिसमें बताया गया है कि C89 में ईवेंट सिस्टम कैसे बनाया जाए, जो सबसे आसान भाषाओं (IMHO) में से एक है, इसे देखें।

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

ईवेंट हैंडलिंग की मूल बातें बहुत सरल हैं।

  • कॉलबैक के साथ ईवेंट पंजीकृत करें
  • ट्रिगर घटना
  • श्रोताओं के माध्यम से देखने के लिए कि क्या कोई मैच है
  • अगर मिल जाए तो फायर हैंडलर
  • दोहराना

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

फिर आपके पास एक ईवेंट डाइजेस्ट (एक साधारण लूप) है, जो उस स्टैक में पहली घटना को पॉप करता है, इसके लिए एक हैंडलर खोजने की कोशिश करता है, और यदि कोई हो, तो उसे परमेस के साथ चलाता है।

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


-2

EventManager- फ़ील्ड के लिए, एक स्थिर चर का उपयोग करें। EventManager के लिए एक सिंगलटन भी एक महान विचार होगा।

आपका दृष्टिकोण अच्छा लगता है, लेकिन इसे धागा-सुरक्षित बनाने के लिए मत भूलना।

"GameEvent" के पहले या बाद में IO-Events को निष्पादित करना अच्छा है, इसलिए एक फ्रेम में हर "GameEvent" एक ही डेटा के साथ काम करता है।


"थ्रेड-बचाने"? हममम
U62

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