2016-09-01 10 views
5

मैं एक एमएमओ गेम के लिए एक आर्किटेक्चर बनाने की कोशिश कर रहा हूं और मैं यह नहीं समझ सकता कि मैं कितने चरों को स्टोर कर सकता हूं क्योंकि मुझे गेमऑब्जेक्ट्स में बहुत सी कॉल किए बिना चाहिए उन्हें एक ही समय में एक तार पर भेजें जब मैं उन्हें अद्यतन करता हूं।सी ++ सदस्य परिवर्तनीय परिवर्तन श्रोताओं (100+ कक्षाएं)

क्या मैं अब है:

Game::ChangePosition(Vector3 newPos) { 
    gameobject.ChangePosition(newPos); 
    SendOnWireNEWPOSITION(gameobject.id, newPos); 
} 

यह कोड बकवास करता है, कठोर, को बनाए रखने को समझते हैं, विस्तार करने के लिए। तो एक चैंपियन उदाहरण के बारे में सोच:

GameObject Champion example

मैं हर चर के लिए कार्यों का एक बहुत बनाने के लिए होगा। और यह सिर्फ इस चैंपियन के लिए सामान्यीकरण है, मेरे पास प्रत्येक चैंपियन प्रकार/"कक्षा" के लिए 1-2 अन्य सदस्य चर हो सकते हैं।

यह सही होगा अगर मैं .NET या 0 समान से OnPropertyChange प्राप्त कर पाऊंगा।

हिमाचल प्रदेश के लिए:: जब मैं इसे अद्यतन, स्वचालित रूप से SendFloatOnWire("HP", hp);

पद के लिए कॉल करें: वास्तुकला मुझे लगता है कि करने के लिए अच्छी तरह से काम करेगा कोशिश कर रहा हूँ अगर मैं कुछ इसी तरह करना पड़ा है जब मैं इसे अद्यतन, स्वचालित रूप से फोन SendVector3OnWire("Position", Position)

नाम के लिए: जब मैं इसे अद्यतन, स्वचालित रूप से फोन SendSOnWire("Name", Name);

क्या हैं वास्तव में SendFloatOnWire, SendVector3OnWire, SendSOnWire? उन कार्यों को जो चार प्रकार के चार बफर में क्रमबद्ध करते हैं।

या विधि 2 (preffered), लेकिन महंगा हो सकता है

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

इसे उच्च स्तरीय गेम सर्वर पर कैसे लागू किया जाएगा और मेरे विकल्प क्या हैं? ऐसे मामलों के लिए कोई उपयोगी किताब?

क्या मैक्रोज़ उपयोगी साबित होंगे? मुझे लगता है कि मुझे कुछ समान स्रोत कोड के बारे में बताया गया था और मुझे लगता है कि यह मैक्रोज़ का इस्तेमाल करता है।

अग्रिम धन्यवाद।

संपादित करें: मुझे लगता है कि मुझे एक समाधान मिला है, लेकिन मुझे नहीं पता कि यह वास्तव में कितना मजबूत है। मुझे इसमें जाना होगा और देखें कि मैं बाद में कहां खड़ा हूं। https://developer.valvesoftware.com/wiki/Networking_Entities

+0

क्या आप वाकई सर्वर खेल चल रहा है, और ग्राहक सिर्फ एक गूंगा रेंडरर नहीं बनना चाहते हैं? इस तरह आपको तार पर इन सभी विशेषताओं को भेजने की ज़रूरत नहीं है (और यह धोखाधड़ी को रोकने में मदद करता है क्योंकि ग्राहक को बेईमान मूल्यों की रिपोर्ट करने के लिए छेड़छाड़ नहीं की जा सकती है)। – Cornstalks

+0

यह ठीक है कि यह कैसे काम करता है, लेकिन मुझे अभी भी क्लाइंट को सूचित करना होगा कि उसे क्या प्रस्तुत करना है। – ioanb7

+0

चेंजपोशन() सिर्फ एक उदाहरण है जहां ग्राहक निर्णय लेता है कि वह कहां जाना चाहता है। यह सिर्फ एक लक्ष्य है, सर्वर तय कर सकता है कि यह मान्य है या नहीं, आदि। मैंने इसे पूरी तरह से एक उदाहरण के रूप में दिया है। – ioanb7

उत्तर

0

कुल मिलाकर निष्कर्ष मैं यहां पहुंचा: स्थिति को अद्यतन करने के बाद एक और कॉल करने के बाद, यह बुरा नहीं है। यह कोड की एक पंक्ति लंबी है, लेकिन यह विभिन्न उद्देश्यों के लिए बेहतर है:

  1. यह स्पष्ट है। आप जानते हैं कि क्या हो रहा है।
  2. आप इसे काम करने के लिए सभी प्रकार के हैक्स बनाकर कोड को धीमा नहीं करते हैं।
  3. आप अतिरिक्त मेमोरी का उपयोग नहीं करते हैं। मैं

तरीके की कोशिश की है: प्रत्येक प्रकार के लिए

  1. होने नक्शे, के रूप में @Christophe द्वारा सुझाव देते हैं। इसका मुख्य दोष यह था कि यह त्रुटि प्रवण नहीं था। आप उसी मानचित्र में एचपी और एचपी घोषित कर सकते थे और इसमें समस्याएं और निराशा की एक और परत शामिल हो सकती थी, जैसे कि प्रत्येक प्रकार के लिए मानचित्र घोषित करना और फिर प्रत्येक चर के पहले नक्शा नाम से।
  2. कुछ SIMILAR का उपयोग वाल्व के engine पर किया गया: यह आपके द्वारा इच्छित प्रत्येक नेटवर्किंग चर के लिए एक अलग वर्ग बनाया गया। फिर, यह आपके द्वारा घोषित मूल प्रकारों को लपेटने के लिए एक टेम्पलेट का उपयोग करता था (int, float, bool) और उस टेम्पलेट के लिए विस्तारित ऑपरेटर भी। इसने बुनियादी कार्यक्षमता के लिए बहुत अधिक मेमोरी और अतिरिक्त कॉल का उपयोग किया।
  3. data mapper का उपयोग करके जो कन्स्ट्रक्टर में प्रत्येक चर के लिए पॉइंटर्स जोड़े गए, और फिर उन्हें ऑफसेट के साथ भेजा। मैंने परियोजना को समय-समय पर छोड़ दिया जब मुझे एहसास हुआ कि कोड भ्रमित और बनाए रखने में मुश्किल है।
  4. हर बार कुछ बदलावों को मैन्युअल रूप से भेजे जाने वाले एक स्ट्रक्चर का उपयोग करना। यह आसानी से protobuf का उपयोग कर किया जाता है। विस्तारित structs भी आसान है।
  5. प्रत्येक टिक, कक्षाओं के डेटा के साथ एक नई संरचना उत्पन्न करती है और इसे भेजती है। यह हमेशा बहुत महत्वपूर्ण सामान रखता है, लेकिन बहुत सारी बैंडविड्थ खाती है।
  6. बढ़ावा से सहायता के साथ प्रतिबिंब का उपयोग करें। यह एक अच्छा समाधान नहीं था।

आखिरकार, मैं 4, और 5 के मिश्रण का उपयोग करने के साथ चला गया। और अब मैं इसे अपने खेल में लागू कर रहा हूं। प्रोटोबफ का एक बड़ा लाभ एक .proto फ़ाइल से structs उत्पन्न करने की क्षमता है, जबकि आपके लिए संरचना के लिए serialization भी प्रदान करता है। यह तेजस्वी तेज है।

उपclasses में दिखाई देने वाले उन विशेष नामित चर के लिए, मेरे पास एक और संरचना है। वैकल्पिक रूप से, प्रोटोबफ से सहायता के साथ मेरे पास गुणों की एक सरणी हो सकती है जो ENUM_KEY_BYTE VALUE जितनी सरल हो। ENUM_KEY_BYTE केवल एक बाइट है जो IS_FLYING, IS_UP, IS_POISONED, और VALUE गुणों के लिए string है।

सबसे महत्वपूर्ण बात यह है कि मैंने इससे सीखा है जितना संभव हो उतना क्रमबद्धता है। अधिक इनपुट & आउटपुट होने के बजाय दोनों सिरों पर अधिक CPU का उपयोग करना बेहतर है।

यदि किसी के पास कोई प्रश्न है, तो टिप्पणी करें और मैं आपकी मदद करने में मेरी पूरी कोशिश करूंगा।

ioanb7

1

विधि 1 पर:

इस तरह के एक दृष्टिकोण एक नक्शे, getters/setters के माध्यम से पहुंचा जा सकता है कि का उपयोग कर लागू करना अपेक्षाकृत "आसान" हो सकता है। सामान्य विचार होगा कुछ की तरह:

class GameCharacter { 
    map<string, int> myints; 
    // same for doubles, floats, strings 
public: 
    GameCharacter() { 
     myints["HP"]=100; 
     myints["FP"]=50; 
    } 
    int getInt(string fld) { return myints[fld]; }; 
    void setInt(string fld, int val) { myints[fld]=val; sendIntOnWire(fld,val); } 
}; 

Online demo

आप अपनी कक्षा में गुण रखना पसंद करते हैं, तो आप संकेत दिए गए या सदस्य संकेत के बजाय मूल्यों के नक्शे के लिए जाना चाहते हैं। निर्माण पर आप मानचित्र को प्रासंगिक पॉइंटर्स के साथ शुरू करेंगे।यदि आप सदस्य चर को बदलने का निर्णय लेते हैं तो आपको हमेशा सेटर के माध्यम से जाना चाहिए।

आप इसे और भी आगे बढ़ सकते हैं और अपने Champion को केवल गुणों और व्यवहारों का एक संग्रह बनाकर, जो मानचित्र के माध्यम से पहुंचा जा सकता है। इस घटक आर्किटेक्चर को Mike McShaffryGame Coding Complete (किसी भी गेम डेवलपर के लिए एक पुस्तक पढ़ने चाहिए) में उजागर किया गया है। कुछ स्रोत कोड डाउनलोड करने के लिए पुस्तक के लिए community site है। आप actor.h और actor.cpp फ़ाइल पर एक नज़र डाल सकते हैं। फिर भी, मैं वास्तव में पुस्तक में पूर्ण स्पष्टीकरण पढ़ने की सलाह देता हूं।

घटकीकरण का लाभ यह है कि आप सभी गुणों के आधार वर्ग में अपने नेटवर्क अग्रेषण तर्क को एम्बेड कर सकते हैं: यह आपके कोड को परिमाण के क्रम से सरल बना सकता है।

विधि 2 पर:

मुझे लगता है कि आधार विचार पूरी तरह से उपयुक्त है, सिवाय इसके कि सभी वस्तुओं की एक पूरी विश्लेषण (या बुरा, संचरण) एक overkill होगा।

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

+2

विधि 2 पर विस्तार करने के लिए, आप उन वस्तुओं के वैश्विक सेट को स्टोर कर सकते हैं जो बासी हैं। जब भी कोई संपत्ति बदलती है, तो इस सेट में बदले में एक पॉइंटर जोड़ें, और नेटवर्क टिक पर, केवल इस सेट में ऑब्जेक्ट्स के माध्यम से चलाएं, अपने सदस्यों को ट्रांसमिट करें, और अंत में सेट को साफ़ करें। यह आपको उन सभी ऑब्जेक्ट्स पर पुन: सक्रिय करने के लिए बचाएगा जो प्रत्येक नेटवर्क को चेक करने के लिए जांचते हैं कि उन्हें अपडेट करने की आवश्यकता है या नहीं। – Rotem

+0

हाय, आपके सुझावों के लिए धन्यवाद। क्या आपको लगता है कि आप कुछ वास्तविक जीवन कोड या छद्म कोड के साथ अपने उत्तर में जोड़ सकते हैं? बदले गए गुणों को चिह्नित करके क्या आपका मतलब है कि मेरे पास प्रत्येक (ऑब्जेक्ट-> propertyName) के लिए शून्य * पॉइंटर्स का गुच्छा होगा? – ioanb7

+0

@ ioanb7 मैंने आगे और स्पष्ट करने के लिए अपना उत्तर संपादित किया है। लेकिन एक महत्वपूर्ण बात: कभी 'शून्य' नहीं! आपके द्वारा समर्थित विभिन्न प्रकारों के लिए आपके 'SendXXXOnWire()' जैसे प्रकार के प्रकार से आपके कार्यों का एक परिवार अस्वीकार हो सकता है (मैंने इसे एक संपादन में दिखाया)। या कोड रिडंडेंसी से बचने के लिए बेहतर टेम्पलेट गेटर्स/सेटर्स का उपयोग करें। वैकल्पिक रूप से आप 'बूस्ट :: संस्करण' या संघ का चयन कर सकते हैं। – Christophe

संबंधित मुद्दे