एक खेल में अभिनेताओं को खुद को खींचने के लिए जिम्मेदार होना चाहिए?


41

मैं खेल के विकास के लिए बहुत नया हूं, लेकिन प्रोग्रामिंग के लिए नहीं।

मैं जावास्क्रिप्ट canvasतत्व का उपयोग करके एक पांग प्रकार के खेल के साथ (फिर से) खेल रहा हूं ।

मैंने एक Paddleऑब्जेक्ट बनाया है जिसमें निम्नलिखित गुण हैं ...

  • width
  • height
  • x
  • y
  • colour

मेरे पास एक Pongऑब्जेक्ट भी है, जिसमें ऐसे गुण हैं ...

  • width
  • height
  • backgroundColour
  • draw()

draw()विधि वर्तमान में रीसेट करने है canvasऔर वह यह है कि जहां एक सवाल आया।

चाहिए Paddleवस्तु एक है draw(), अपने ड्राइंग के लिए विधि जिम्मेदार या चाहिए draw()की Pongवस्तु अपने अभिनेताओं ड्राइंग के लिए जिम्मेदार हो (मुझे लगता है कि सही शब्द है, कृपया मुझे सही अगर मैं गलत हूँ)।

मुझे लगा कि यह Paddleखुद को आकर्षित करने के लिए अनुकूल होगा, जैसा कि मैंने दो वस्तुओं को पलटा, Playerऔर Enemy। यदि ऐसा नहीं थे Pongकी draw(), मैं इसी तरह के कोड दो बार लिखने की ज़रूरत होगी।

यहां सबसे अच्छा अभ्यास क्या है?

धन्यवाद।


इसी प्रकार के प्रश्न: gamedev.stackexchange.com/questions/13492/...
MichaelHouse

जवाबों:


49

दो मुख्य कारणों से अभिनेता खुद को आकर्षित करना एक अच्छा डिज़ाइन नहीं है:

1) यह एकल जिम्मेदारी सिद्धांत का उल्लंघन करता है , क्योंकि उन अभिनेताओं के पास संभवतः एक और काम था, इससे पहले कि आप उन्हें कोड सौंप दें।

2) यह विस्तार मुश्किल बनाता है; यदि प्रत्येक अभिनेता अपने स्वयं के ड्राइंग को लागू करता है, और आपको सामान्य तरीके से आकर्षित करने के तरीके को बदलने की आवश्यकता है , तो आपको बहुत सारे कोड को संशोधित करना पड़ सकता है। विरासत के अति प्रयोग से बचने से कुछ हद तक यह कम हो सकता है, लेकिन पूरी तरह से नहीं।

ड्राइंग रेंडर करना आपके रेंडरर के लिए बेहतर है। आखिरकार, यह एक रेंडरर होने का मतलब है। रेंडरर की ड्रा विधि में "रेंडर डिस्क्रिप्शन" ऑब्जेक्ट लेना चाहिए, जिसमें वह चीज़ है जो आपको किसी चीज़ को रेंडर करने के लिए आवश्यक है। (शायद साझा) ज्यामिति डेटा, उदाहरण-विशिष्ट परिवर्तनों या रंग, एट सिटेरा जैसे भौतिक गुणों के संदर्भ। यह तब खींचता है, और परवाह नहीं करता है कि विवरण प्रस्तुत करना "होना चाहिए" है।

आपके अभिनेता तब रेंडर विवरण पर पकड़ बना सकते हैं जो वे खुद बनाते हैं। चूँकि अभिनेता आम तौर पर तर्क प्रसंस्करण प्रकार होते हैं, इसलिए वे विवरण में राज्य परिवर्तनों को विवरण के अनुसार प्रस्तुत कर सकते हैं - उदाहरण के लिए, जब कोई अभिनेता नुकसान उठाता है तो यह इंगित करने के लिए उसके रेंडर विवरण का रंग लाल कर सकता है।

तो आप बस हर दृश्यमान अभिनेता को पुनरावृत्त कर सकते हैं, रेंडरर में उनके रेंडर विवरणों को संलग्न कर सकते हैं, और उसे यह काम करने दे सकते हैं (मूल रूप से; आप इसे आगे भी सामान्य कर सकते हैं)।


14
+1 "रेंडरर ड्राइंग कोड" के लिए, लेकिन एकल जिम्मेदारी सिद्धांत के लिए -1, जिसने प्रोग्रामर को अच्छे से अधिक नुकसान पहुंचाया है । यह सही विचार (चिंताओं को अलग करना) है , लेकिन जिस तरह से यह कहा गया है ("हर वर्ग की केवल एक ज़िम्मेदारी होनी चाहिए, और / या बदलने का केवल एक कारण") बस गलत है
ब्लूराजा - डैनी पफ्लुगुफ्ट

2
-1 के लिए 1), जैसा कि ब्लूराज ने बताया, यह सिद्धांत आदर्शवादी है, लेकिन व्यावहारिक नहीं है। -1 के लिए 2) क्योंकि यह विस्तार को और अधिक कठिन नहीं बनाता है। यदि आपको अपना पूरा रेंडरिंग इंजन बदलना है, तो आपके पास अपने अभिनेता कोड में जो थोड़ा बहुत है, उसे बदलने के लिए आपके पास बहुत अधिक कोड होने वाले हैं। मैं बहुत पसंद करेंगे actor.draw(renderer,x,y)की तुलना में renderer.draw(actor.getAttribs(),x,y)
corsiKa

1
अच्छा उत्तर! अच्छी तरह से "आप एकल जिम्मेदारी सिद्धांत का उल्लंघन नहीं करेंगे" मेरे डिकोग्ल्यू के अंदर नहीं है, लेकिन अभी भी ध्यान में रखना एक अच्छा सिद्धांत है
FxIII

@glowcoder बात नहीं है, तो आप अभिनेता (वापसी) को बनाए रख सकते हैं, जिसे {रेंडरर। वापस (मेष, अट्रिब्यूशन, ट्रांसफॉर्म) के रूप में परिभाषित किया गया है; }। ओपनजीएल में, मैं struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; }अपने रेंडर के लिए कम या ज्यादा बनाए रखता हूं। इस तरह रेंडरर परवाह नहीं करता है कि डेटा क्या दर्शाता है, यह सिर्फ इसे संसाधित करता है। इस जानकारी के आधार पर, मैं यह भी तय कर सकता हूं कि समग्र GPU कॉल को कम करने के लिए ड्रॉ कॉल के क्रम को क्रमबद्ध करना है या नहीं।
डेक्लेरेटेडकवि

16

आगंतुक पैटर्न यहाँ उपयोगी हो सकता है।

आप क्या कर सकते हैं एक रेंडरर इंटरफ़ेस है जो जानता है कि प्रत्येक ऑब्जेक्ट को कैसे आकर्षित किया जाए और प्रत्येक अभिनेता में एक "अपने आप को आकर्षित करें" विधि जो निर्धारित करती है कि कौन सी (विशिष्ट) रेंडरर विधि कॉल करने के लिए है, जैसे।

interface Renderer {
    void drawPaddle(Player owner, Rectangle position);
    // Note: the Renderer chooses the Color based on which player the paddle belongs to

    // Also drawBackground, drawBall etc.
}

interface Actor {
    void draw(Renderer renderer);
}

class Paddle implements Actor {
    void draw(Renderer renderer) {
        renderer.drawPaddle(this.owner, this.getBounds());
    }
}

इस तरह यह अभी भी एक और ग्राफिक्स लाइब्रेरी या फ्रेमवर्क में पोर्ट करना आसान है (मैंने एक बार स्विंगिंग / जावा 2 डी से एलडब्ल्यूजेजीएल के लिए एक गेम को पोर्ट किया था और मुझे बहुत खुशी हुई कि मैंने इस पैटर्न का उपयोग एक Graphics2Dआसपास से गुजरने के बजाय किया था ।)

एक और लाभ है: रेंडरर को किसी भी अभिनेता कोड से अलग से परीक्षण किया जा सकता है


2

अपने उदाहरण में आप पांग वस्तुओं को ड्रॉ लागू करना चाहते हैं () और खुद को प्रस्तुत करना।

यद्यपि आप इस आकार की एक परियोजना में कोई महत्वपूर्ण लाभ नहीं देखेंगे, आम तौर पर खेल तर्क और उनके दृश्य प्रतिनिधित्व (प्रतिपादन) को अलग करना एक सार्थक गतिविधि है।

इसका मतलब है कि आपके पास आपके गेम ऑब्जेक्ट होंगे जो अपडेट हो सकते हैं () 'd' लेकिन उन्हें इस बात का कोई अंदाजा नहीं है कि वे कैसे प्रस्तुत किए जाते हैं, वे केवल सिमुलेशन से चिंतित हैं।

तब आपके पास एक PongRenderer () वर्ग होगा जिसमें एक Pong ऑब्जेक्ट का संदर्भ होता है, और इसके बाद Pong () वर्ग को रेंडर करने का प्रभार लेता है, इसमें Paddles प्रदान करना शामिल हो सकता है, या इसकी देखभाल करने के लिए PaddleRenderer वर्ग का होना।

इस मामले में चिंताओं का पृथक्करण एक काफी स्वाभाविक है जिसका अर्थ है कि आपकी कक्षाएं कम फूली हुई हो सकती हैं, और यह संशोधित करना आसान है कि चीजें कैसे प्रदान की जाती हैं, यह अब पदानुक्रम का पालन नहीं करना है जो आपका अनुकरण करता है।


-1

यदि आप इसे Pong'ड्रॉ' () में करते हैं, तो आपको कोड को डुप्लिकेट करने की आवश्यकता नहीं होगी - बस Paddleअपने प्रत्येक पैडल के लिए 's ड्रॉ' (') फंक्शन को कॉल करें । तो आपके Pongड्रॉ में () आपके पास होगा

humanPaddle.draw();
compPaddle.draw();

-1

हर ऑब्जेक्ट में अपना ड्रॉ फंक्शन होना चाहिए जिसे गेम अपडेट कोड या ड्रॉ कोड कहा जाना चाहिए। पसंद

class X
{
  public void Draw( )
  {
     // Do something 
  } 
}

class Y
{
  public void Draw( )
   { // Do Something 
   } 
}

class Game
{
  X objX;
  Y objY;

  @Override
  public void OnDraw( )
  {
      objX.Draw( );
      objY.Draw( ); 
  } 
}

यह एक कोड नहीं है, बल्कि केवल यह दिखाने के लिए है कि वस्तुओं को कैसे चित्रित किया जाना चाहिए।


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

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