इस इकाई प्रणाली को कैसे नेटवर्क करें?


33

मैंने एक एफपीएस के लिए एक इकाई प्रणाली तैयार की है। यह मूल रूप से इस तरह काम करता है:

हमारे पास एक "दुनिया" है, जिसे गेमवर्ल्ड कहा जाता है। यह GameObject की एक सरणी के साथ-साथ ComponentManager की एक सरणी रखता है।

GameObject घटक की एक सरणी रखती है। यह एक घटना तंत्र भी प्रदान करता है जो वास्तव में सरल है। घटक स्वयं इकाई को एक घटना भेज सकते हैं, जो सभी घटकों को प्रसारित की जाती है।

घटक मूल रूप से कुछ ऐसा है जो गेमऑबजेक्ट को कुछ गुण प्रदान करता है, और चूंकि गेम ऑबजेक्ट वास्तव में सिर्फ उनमें से एक कंटेनर है, जो कुछ भी एक गेम ऑब्जेक्ट के साथ करना है जो अवयवों में होता है। उदाहरणों में ViewComponent, PhysicsComponent और LogicComponent शामिल हैं। यदि उनके बीच संचार की आवश्यकता है, तो वह घटनाओं के उपयोग के माध्यम से किया जा सकता है।

ComponentManager बस घटक की तरह एक अंतरफलक है, और प्रत्येक घटक वर्ग के लिए, आम तौर पर एक ComponentManager वर्ग होना चाहिए। ये घटक प्रबंधक घटकों को बनाने और XML-फ़ाइल जैसी किसी चीज़ से पढ़ी गई संपत्तियों के साथ आरंभ करने के लिए जिम्मेदार हैं।

ComponentManager घटकों के बड़े पैमाने पर अद्यतन का भी ध्यान रखता है, जैसे कि PhysicsComponent जहाँ मैं एक बाहरी पुस्तकालय (जो दुनिया में सब कुछ एक बार में करता है) का उपयोग करूँगा।

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

अब मेरी समस्या आती है: मैं मल्टीप्लेयर गेम के लिए इसका उपयोग करने की कोशिश करने जा रहा हूं। मुझे नहीं पता कि इस से कैसे संपर्क किया जाए।

सबसे पहले: ग्राहकों को शुरू से ही कौन सी संस्थाएं चाहिए? मुझे यह समझाने के साथ शुरू करना चाहिए कि एक एकल-खिलाड़ी इंजन यह कैसे निर्धारित करेगा कि संस्थाएं क्या बनाएं।

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

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

जब आप उस स्तर को लोड करते हैं, तो यह सभी संस्थाओं को अलग कर देता है। सरल लगता है, एह?

अब, नेटवर्किंग के लिए मैं कई समस्याओं में भाग लेता हूं। सबसे पहले, ग्राहक को शुरू से ही कौन सी इकाइयाँ मौजूद होनी चाहिए? यह मानते हुए कि सर्वर और क्लाइंट दोनों के पास स्तर की फाइल है, क्लाइंट स्तर में सभी संस्थाओं को भी अस्थिर कर सकता है, भले ही वे सर्वर पर गेम के नियमों के प्रयोजनों के लिए हों।

एक और संभावना यह है कि जैसे ही सर्वर इसके बारे में जानकारी भेजता है, ग्राहक एक संस्था को भेज देता है, और इसका मतलब है कि ग्राहक के पास केवल वही इकाइयां होंगी जिनकी उसे जरूरत है।

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

और अंत में, नेटवर्किंग को इंजन में कैसे इंजेक्ट किया जाना चाहिए? मैं एक घटक सोच रहा हूं, NetworkComponent, जिसे हर इकाई में इंजेक्ट किया जाता है जिसे नेटवर्क माना जाता है। लेकिन नेटवर्क घटक को कैसे पता होना चाहिए कि नेटवर्क के लिए चर क्या हैं, और उन तक कैसे पहुंचें, और अंत में क्लाइंट पर संगत नेटवर्क घटक को कैसे पता चले कि नेटवर्क चर कैसे बदलना है?

मुझे इस तक पहुँचने में बहुत परेशानी हो रही है। यदि आप रास्ते में मेरी मदद करते हैं तो मैं वास्तव में सराहना करूंगा। मैं कैसे घटक प्रणाली के डिजाइन में सुधार करने के लिए पर सुझाव के लिए खुला हूँ, ताकि सुझाव देने से डरो मत।

जवाबों:


13

यह एक भगवान का लानत (क्षमा) है जिसमें बहुत सारे विवरण +1 वाले प्रश्न हैं। निश्चित रूप से उन लोगों की मदद करने के लिए पर्याप्त है जो उस पर ठोकर खाते हैं।

मैं ज्यादातर भौतिकी डेटा नहीं भेजने के बारे में अपने 2 सेंट जोड़ना चाहता था !! मैं ईमानदारी से इस पर जोर नहीं दे सकता। यहां तक ​​कि अगर आपके पास यह अभी तक अनुकूलित है, तो आप व्यावहारिक रूप से 40 क्षेत्रों को भेज सकते हैं जो सूक्ष्म टकराव के साथ चारों ओर उछलते हैं और यह एक झटकों वाले कमरे में पूरी गति से जा सकता है जो फ्रेम दर को भी कम नहीं करता है। मैं आपके "डेल्टा-कम्प्रेशन / एन्कोडिंग" का प्रदर्शन करने की बात कर रहा हूँ, जिसे आप डेटा-डिफरेंसिंग के रूप में भी जानते हैं। यह काफी कुछ वैसा ही है जैसा मैं लाने वाला था।

डेड रेकनिंग वी.एस. डेटा विभेदक: वे अलग-अलग पर्याप्त हैं और वास्तव में समान विधियों पर कब्जा नहीं करते हैं, जिसका अर्थ है कि आप अनुकूलन को और अधिक बढ़ाने के लिए दोनों को लागू कर सकते हैं! नोट: मैंने उन दोनों का एक साथ उपयोग नहीं किया है, लेकिन दोनों के साथ काम किया है।

डेल्टा एन्कोडिंग या डेटा-अलग-अलग: सर्वर उस डेटा को वहन करता है जो ग्राहक जानते हैं, और पुराने डेटा के बीच के अंतर को ही भेजता है और ग्राहक को क्या बदलना चाहिए। उदाहरण के लिए छद्म-> एक उदाहरण में आप डेटा "315 435 222 3546 33" भेज सकते हैं, जब डेटा पहले से ही "310 435 210 4000 40" हो, तो कुछ केवल थोड़े से बदले जाते हैं, और एक बिल्कुल भी नहीं बदला जाता है! इसके बजाय, आप (डेल्टा में) "5 0 12 -454 -7" भेजेंगे जो काफी कम है।

बेहतर उदाहरण कुछ ऐसा हो सकता है जो इससे बहुत अधिक परिवर्तन करता है, उदाहरण के लिए मैं कह सकता हूं कि मेरे पास अभी 45 लिंक की गई वस्तुओं के साथ एक लिंक की गई सूची है। मैं उनमें से 30 को मारना चाहता हूं, इसलिए मैं ऐसा करता हूं, फिर सभी को भेजता हूं कि नया पैकेट डेटा क्या है, जो सर्वर को धीमा कर देगा अगर यह पहले से ही इस तरह की चीजें करने के लिए नहीं बनाया गया था, और ऐसा इसलिए हुआ क्योंकि यह कोशिश कर रहा था उदाहरण के लिए खुद को सही करने के लिए। डेल्टा एन्कोडिंग में, आप बस (छद्म) "list.kill 30 at 5" डालेंगे और यह 5 वीं के बाद सूची से 30 ऑब्जेक्ट निकाल देगा फिर डेटा को प्रमाणित करेगा, लेकिन सर्वर के बजाय प्रत्येक क्लाइंट पर।

पेशेवरों: (केवल एक के बारे में अभी सोच सकते हैं)

  1. गति: स्पष्ट रूप से मेरे अंतिम उदाहरण में मैंने वर्णन किया है। यह पिछले उदाहरण की तुलना में बहुत अधिक अंतर होगा। सामान्य तौर पर मैं अनुभव से यह नहीं कह सकता कि उनमें से कौन सा अधिक सामान्य होगा, क्योंकि मैं मृत गणना के साथ बहुत अधिक काम करता हूं

विपक्ष:

  1. यदि आप अपना सिस्टम अपडेट कर रहे हैं और कुछ और डेटा जोड़ना चाहते हैं, जिसे डेल्टा के माध्यम से संपादित किया जाना चाहिए, तो आपको उस डेटा को बदलने के लिए नए फ़ंक्शन बनाने होंगे! (पहले की तरह "list.kill 30 at 5" ओह शिट मुझे क्लाइंट के लिए एक पूर्ववत विधि की आवश्यकता है! "list.kill पूर्ववत करें")

डेड रेकनिंग: बस कहा गया है, यहाँ एक सादृश्य है। मैं किसी के लिए एक मानचित्र लिख रहा हूं कि किसी स्थान पर कैसे पहुंचा जाए, और मैं केवल उन बिंदुओं को शामिल कर रहा हूं, जहां सामान्य रूप से जाना है, क्योंकि यह काफी अच्छा है (निर्माण पर रोक, बाएं मुड़ें)। किसी के नक्शे में सड़क के नाम और बाएं मुड़ने के लिए कितने डिग्री शामिल हैं, क्या यह बिल्कुल आवश्यक है? (नहीं...)

डेड रेकिंग वह जगह है जहां प्रत्येक क्लाइंट के पास एक एल्गोरिथ्म होता है जो प्रति ग्राहक निरंतर होता है। डेटा बहुत ज्यादा सिर्फ यह कहकर बदल दिया जाता है कि किस डेटा में बदलाव की जरूरत है, और यह कैसे करना है। क्लाइंट डेटा को अपने आप बदल देता है। एक उदाहरण यह है कि अगर मेरे पास एक ऐसा चरित्र है जो मेरा खिलाड़ी नहीं है, लेकिन मेरे साथ खेलने वाले किसी अन्य व्यक्ति द्वारा स्थानांतरित किया जा रहा है, तो मुझे डेटा को हर फ्रेम में अपडेट नहीं करना चाहिए क्योंकि बहुत सारा डेटा सुसंगत है!

कहते हैं कि मेरा चरित्र किसी दिशा में आगे बढ़ रहा है, कई सर्वर क्लाइंट को डेटा भेजेंगे जो कहता है (लगभग प्रति फ्रेम) जहां खिलाड़ी है, और यह चलती है (एनीमेशन कारणों से)। इतना अनावश्यक डेटा है! मुझे हर एक फ्रेम को अपडेट करने की आवश्यकता क्यों है, यूनिट कहां है और यह किस दिशा में है और यह किस दिशा में बढ़ रहा है? सीधे शब्दों में कहें: मैं नहीं। जब दिशा बदलती है, जब क्रिया बदलती है (isMoving = true?) और ऑब्जेक्ट क्या होता है, आप केवल क्लाइंट को अपडेट करते हैं! फिर प्रत्येक क्लाइंट ऑब्जेक्ट को तदनुसार स्थानांतरित करेगा।

व्यक्तिगत रूप से यह सामान्य ज्ञान की रणनीति है। यह कुछ ऐसा है जिसे मैंने सोचा था कि मैं एक लंबे समय के साथ आने में चतुर था, जो हर समय इस्तेमाल किया जाता था।

जवाब

काफी स्पष्ट होने के लिए, जेम्स की पोस्ट पढ़ें और डेटा के बारे में मैंने जो कहा है उसे पढ़ें। हाँ, आपको सबसे अधिक डेल्टा-एन्कोडिंग का उपयोग करना चाहिए, लेकिन मृत रेकिंग का उपयोग करने के बारे में भी सोचें।

व्यक्तिगत रूप से मैं क्लाइंट पर डेटा को तुरंत भेज दूंगा, जब वह सर्वर से इसके बारे में जानकारी प्राप्त करता है (आपके द्वारा सुझाए गए कुछ)।

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

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

जैसे कि यह कैसे पता होना चाहिए कि नेटवर्क में कौन से चर हैं, मेरे पास एक घटक हो सकता है जो वास्तव में एक सब-ऑब्जेक्ट है, और इसे ऐसे घटक दें जो आप नेटवर्क को पसंद करेंगे। एक और विचार यह है कि यह न केवल व्यक्तिगत रूप से होशियार है AddComponent("whatever")बल्कि AddNetComponent("and what have you")इसलिए भी है ।


यह एक हास्यास्पद लंबा जवाब है! मुझे उस पर बहुत अफसोस है। जैसा कि मेरा इरादा केवल थोड़ी मात्रा में ज्ञान की आपूर्ति करना है और फिर कुछ चीजों के बारे में मेरे 2 सेंट। तो मैं समझता हूं कि यह नोट करने के लिए बहुत कम अनावश्यक हो सकता है।
यहोशू हेजेज

3

एक टिप्पणी लिखने जा रहा था, लेकिन फैसला किया कि यह एक जवाब के लिए पर्याप्त जानकारी हो सकती है।

सबसे पहले, इस तरह के एक अच्छी तरह से लिखित प्रश्न के लिए +1 विवरण द्वारा न्याय करने के लिए विवरण के टन के साथ।

डेटा लोडिंग के लिए मेरे पास क्लाइंट को दुनिया फ़ाइल से लोड करना होगा। यदि आपकी संस्थाओं में Ids हैं जो डेटा फ़ाइल से आते हैं तो मैं उन्हें डिफ़ॉल्ट रूप से लोड भी करूंगा ताकि आपका नेटवर्किंग सिस्टम केवल उन्हें यह जानने के लिए संदर्भित कर सके कि यह किन वस्तुओं की बात कर रहा है। सभी को एक ही प्रारंभिक डेटा लोड करने का मतलब होना चाहिए कि उन सभी वस्तुओं के लिए समान Ids हैं।

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

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

उम्मीद है की यह मदद करेगा।


तो, आप क्या कह रहे हैं कि जिन घटकों को नेटवर्क किया जाना चाहिए, उन्हें कुछ इस तरह के इंटरफ़ेस को लागू करना चाहिए ?: शून्य SetNetworkedVariable (स्ट्रिंग नाम, NetworkedVariable value); NetworkedVariable GetNetworkedVariable (स्ट्रिंग नाम); जहां NetworkedVariable का उपयोग इंटरपोलिंग और अन्य नेटवर्क सामान के प्रयोजनों के लिए किया जाता है। मैं नहीं जानता कि कैसे उन घटकों की पहचान करें जो इसे लागू करते हैं। मैं रनटाइम प्रकार की पहचान का उपयोग कर सकता था, लेकिन यह मुझे बदसूरत लगता है।
कार्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.