GameObject वर्ग के बाहर तर्क प्रस्तुत करने के लिए रणनीति


10

गेम बनाते समय आप अक्सर निम्नलिखित गेम ऑब्जेक्ट बनाते हैं जिसमें से सभी निकाय वारिस होते हैं:

public class GameObject{
    abstract void Update(...);
    abstract void Draw(...);
}

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

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

अगर मैं रेंडर की रणनीति को आगे से स्थगित करने के लिए बदल सकता था तो मुझे बहुत सी गेम ऑब्जेक्ट को अपडेट करना होगा। और मेरे द्वारा बनाई गई खेल वस्तुएं पुन: प्रयोज्य नहीं हैं क्योंकि वे हो सकते हैं। बेशक विरासत और / या रचना मुझे कोड डुप्लीकेशन से लड़ने में मदद कर सकती है और कार्यान्वयन को बदलना थोड़ा आसान बना सकती है लेकिन फिर भी यह कमी महसूस होती है।

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

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

वैसे भी चलो पुनर्कथन करते हैं, मुझे दिलचस्पी है कि निम्नलिखित डिज़ाइन लक्ष्यों को कैसे प्राप्त किया जा सकता है।

  • खेल वस्तु में कोई प्रतिपादन तर्क नहीं
  • गेम ऑब्जेक्ट्स और रेंडर इंजन के बीच ढीली कपलिंग
  • सभी जानने वाले रेंडर नहीं
  • रेंडर इंजन के बीच अधिमानतः रनटाइम स्विचिंग

आदर्श प्रोजेक्ट सेटअप एक अलग 'गेम लॉजिक' होगा और लॉजिक प्रोजेक्ट को प्रस्तुत करना होगा जो एक दूसरे को संदर्भित करने की आवश्यकता न हो।

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

जवाबों:


7

अनचाहे करने के लिए एक त्वरित पहला कदम:

गेम ऑब्जेक्ट्स एक पहचानकर्ता का संदर्भ देते हैं कि उनके दृश्य क्या हैं, लेकिन डेटा नहीं, चलो एक स्ट्रिंग की तरह कुछ सरल कहें। उदाहरण: "human_male"

रेंडरर "human_male" संदर्भों को लोड करने और बनाए रखने के लिए ज़िम्मेदार है और उपयोग करने के लिए एक ऑब्जेक्ट को वापस पास करना।

भयानक छद्मकोड में उदाहरण:

GameObject( initialization parameters )
  me.render_handle = Renderer_Create( parameters.render_string )

- elsewhere
Renderer_Create( string )

  new data handle = Resources_Load( string );
  return new data handle

- some time later
GameObject( something happens to me parameters )
  me.state = something.what_happens
  Renderer_ApplyState( me.render_handle, me.state.effect_type )

- some time later
Renderer_Render()
  for each renderable thing
    for each rendering back end
        setup graphics for thing.effect
        render it

- finally
GameObject_Destroy()
  Renderer_Destroy( me.render_handle )

उस गड़बड़ी के लिए क्षमा करें, वैसे भी आपकी शर्तों को पूरा किया जाता है जो वास्तविक दुनिया की वस्तुओं और OOP में जिम्मेदारियों के आधार पर चीजों को देखने के आधार पर शुद्ध OOP से दूर होते हैं।

  • गेम ऑब्जेक्ट में कोई रेंडरिंग लॉजिक नहीं किया गया (किया गया, सभी ऑब्जेक्ट जानता है कि यह एक हैंडल है ताकि यह खुद पर प्रभाव लागू कर सके)
  • खेल वस्तुओं और रेंडर इंजन के बीच ढीली युग्मन (किया, सभी संपर्क एक सार संभाल के माध्यम से होता है, उन राज्यों को लागू किया जा सकता है और उन राज्यों के साथ क्या करना है)
  • सभी रेंडरिंग नहीं (किया, केवल अपने बारे में जानता है)
  • रेंडर इंजनों के बीच अधिमानतः रनटाइम स्विचिंग (यह Renderer_Render () चरण में किया जाता है, आपको दोनों बैक एंड को लिखना होगा)

वे कीवर्ड जिन्हें आप खोज सकते हैं कि कक्षाओं के एक साधारण रीफैक्टरिंग से परे जाने के लिए "यूनिट / कंपोनेंट सिस्टम" और "डिपेंडेंसी इंजेक्शन" होंगे और पुराने ब्रेन गियर्स कताई पाने के लिए संभवतः "एमवीसी" जीयूआई पैटर्न।


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

2

मैंने अपने स्वयं के इंजन के लिए जो कुछ किया है वह सब कुछ मॉड्यूल में समूहित करना है। तो मेरे पास मेरी GameObjectकक्षा है और यह एक संभालता है:

  • ModuleSprite - ड्राइंग स्प्राइट
  • ModuleWeapon - फायरिंग गन
  • ModuleScriptingBase - स्क्रिप्टिंग
  • ModuleParticles - कण प्रभाव
  • ModuleCollision - टक्कर का पता लगाने और प्रतिक्रिया

इसलिए मेरे पास एक Playerक्लास और एक Bulletक्लास है। दोनों से प्राप्त होते हैं GameObjectऔर इसमें जोड़े जाते हैं Scene। लेकिन Playerनिम्नलिखित मॉड्यूल हैं:

  • ModuleSprite
  • ModuleWeapon
  • ModuleParticles
  • ModuleCollision

और Bulletइन मॉड्यूल है:

  • ModuleSprite
  • ModuleCollision

चीजों को व्यवस्थित करने का यह तरीका "डायमंड ऑफ डेथ" से बचता है जहां आपके पास एक Vehicle, एक VehicleLandऔर एक है VehicleWaterऔर अब आप एक चाहते हैं VehicleAmphibious। इसके बजाय आपके पास एक है Vehicleऔर यह एक ModuleWaterऔर एक हो सकता है ModuleLand

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

मेरे दृश्य में, मैं निम्नलिखित कार्य करता हूं:

  • Updateसभी GameObjectहैंडल के लिए कॉल करें ।
  • उन लोगों के लिए टकराव की जाँच और टक्कर की प्रतिक्रिया करें, जिनके पास ModuleCollisionसंभाल है।
  • भौतिकी के बाद अपनी अंतिम स्थिति के बारे में बताने के UpdatePostलिए सभी GameObjectहैंडल के लिए कॉल करें ।
  • उन वस्तुओं को नष्ट करें जिनके पास अपना ध्वज सेट है।
  • सूची में नई वस्तुओं को m_ObjectsCreatedसूची से जोड़ें m_Objects

और मैं इसे और व्यवस्थित कर सकता हूं: वस्तु के बजाय मॉड्यूल द्वारा। तब मैं एक सूची प्रस्तुत करूंगा ModuleSprite, एक सूची को अद्यतन करूंगा ModuleScriptingBaseऔर सूची के साथ टकराव करूंगा ModuleCollision


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

अरे हाँ। यह इस प्रणाली के लिए नकारात्मक है: यदि आपके पास एक विशिष्ट आवश्यकता है GameObject(उदाहरण के लिए स्प्राइट्स के "सांप" को प्रस्तुत करने का एक तरीका) तो आपको या तो ModuleSpriteउस विशिष्ट कार्यक्षमता के लिए एक बच्चा बनाने की आवश्यकता होगी ( ModuleSpriteSnake) या पूरी तरह से एक नया मॉड्यूल जोड़ें; ModuleSnake)। सौभाग्य से वे केवल संकेत कर रहे हैं, लेकिन मैं कोड जहां देखा है GameObjectसचमुच किया सब कुछ एक वस्तु कर सकता है।
नाइट ६६६
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.