मेरी वास्तुकला के लिए कई विरासत के विकल्प (एक रीयलटाइम रणनीति खेल में एनपीसी)?


11

कोडिंग वास्तव में इतना कठिन नहीं है । कठिन हिस्सा कोड लिखना है जो समझ में आता है, पठनीय और समझने योग्य है। इसलिए मैं एक बेहतर डेवलपर प्राप्त करना चाहता हूं और कुछ ठोस वास्तुकला बनाना चाहता हूं।

इसलिए मैं वीडियो गेम में एनपीसी के लिए एक आर्किटेक्चर बनाना चाहता हूं । यह Starcraft की तरह एक रीयलटाइम रणनीति खेल है, साम्राज्यों की आयु, कमान और विजय, आदि। .. तो मैं NPCs के विभिन्न प्रकार होंगे। एक एनपीसी कई क्षमताओं इनमें से (विधि) के लिए हो सकते हैं: Build(), Farm()और Attack()

उदाहरण:
कार्यकर्ता कर सकते हैं Build()और Farm()
योद्धा कर सकते हैं Attack()
नागरिक कर सकते हैं Build(), Farm()और Attack()
मछुआरे कर सकते हैं Farm()औरAttack()

मुझे उम्मीद है कि अब तक सब कुछ स्पष्ट है।

इसलिए अब मेरे पास मेरे एनपीसी प्रकार और उनकी क्षमताएं हैं। लेकिन तकनीकी / प्रोग्राम पहलू पर आने देता है।
मेरे विभिन्न प्रकार के एनपीसी के लिए एक अच्छा प्रोग्रामेटिक आर्किटेक्चर क्या होगा?

ठीक है मैं एक आधार वर्ग हो सकता है। वास्तव में मुझे लगता है कि यह DRY सिद्धांत के साथ एक अच्छा तरीका है । इसलिए मेरे पास WalkTo(x,y)मेरे आधार वर्ग की तरह विधियां हो सकती हैं क्योंकि प्रत्येक एनपीसी को स्थानांतरित करने में सक्षम होगा। लेकिन अब चलिए असली समस्या पर आते हैं। मैं अपनी क्षमताओं को कहां लागू करूं? (याद रखें: Build(), Farm()और Attack())

चूँकि क्षमताओं में एक ही तर्क समाहित होगा, इसलिए यह प्रत्येक एनपीसी (कार्यकर्ता, योद्धा, ..) के लिए लागू करने के लिए कष्टप्रद / डीआरवाई सिद्धांत को तोड़ देगा।

ठीक है मैं बेस क्लास के भीतर क्षमताओं को लागू कर सकता हूं । इस तर्क के कुछ प्रकार की आवश्यकता होगी सत्यापन अगर एक एनपीसी क्षमता एक्स उपयोग कर सकते हैं कि IsBuilder, CanBuild, .. मुझे लगता है कि यह स्पष्ट है कि मैं क्या व्यक्त करना चाहता हूँ।
लेकिन मैं इस विचार के साथ बहुत अच्छा महसूस नहीं करता। यह बहुत अधिक कार्यक्षमता के साथ एक फूला हुआ बेस क्लास लगता है ।

मैं प्रोग्रामिंग भाषा के रूप में C # का उपयोग करता हूं। इसलिए कई विरासत यहाँ एक विकल्प नहीं है। मीन्स: अतिरिक्त बेस क्लास जैसे Fisherman : Farmer, Attackerकाम नहीं करेंगे।


3
मैं इस उदाहरण को देख रहा था जो इस के समाधान की तरह लगता है: en.wikipedia.org/wiki/Composition_over_inheritance
Shann Mclean

जवाबों:


14

संरचना और इंटरफ़ेस वंशानुक्रम शास्त्रीय बहु विरासत के सामान्य विकल्प हैं।

सब कुछ है कि आप ऊपर वर्णित है कि शब्द "कर सकते हैं" के साथ शुरू होता है एक क्षमता है कि एक अंतरफलक के साथ, के रूप में ICanBuild, या में प्रतिनिधित्व किया जा सकता है ICanFarm। आप उन सभी इंटरफेसों में से कई को विरासत में प्राप्त कर सकते हैं जितना आपको लगता है कि आपको ज़रूरत है।

public class Worker: ICanBuild, ICanFarm
{
    #region ICanBuild Implementation
    // Build
    #endregion

    #region ICanFarm Implementation
    // Farm
    #endregion
}

आप अपने वर्ग के निर्माता के माध्यम से "जेनेरिक" भवन और खेती की वस्तुओं में गुजर सकते हैं। यहीं से रचना आती है।


बस ज़ोर से सोच: 'संबंध' हैं (आंतरिक) हो गया है के बजाय है (कार्यकर्ता बिल्डर बजाय है कार्यकर्ता बिल्डर है)। आपके द्वारा समझाया गया उदाहरण / पैटर्न मेरी समस्या को हल करने के लिए एक अच्छा डिकॉउंडेड तरीका समझ में आता है। लेकिन मुझे इस रिश्ते को पाने के लिए कठिन समय है।
ब्रेटेटेट

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

1
कार्यकर्ता अभी भी एक बिल्डर है, क्योंकि आपको विरासत में मिला है ICanBuild। आपके पास निर्माण के लिए उपकरण भी हैं, वस्तु पदानुक्रम में द्वितीयक चिंता का विषय है।
रॉबर्ट हार्वे

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

4
@ ब्रेटेट यह बिल्ड, फ़ार्म, अटैक, हंट, इत्यादि को कौशल के रूप में लागू करने में मदद कर सकता है , जो आपके पात्रों के पास है। BuildSkill, FarmSkill, AttackSkill, आदि फिर रचना बहुत अधिक समझ में आता है।
एरिक किंग

4

जैसा कि अन्य पोस्टरों ने उल्लेख किया है कि एक घटक वास्तुकला इस समस्या का समाधान हो सकता है।

class component // Some generic base component structure
{
  void update() {} // With an empty update function
} 

इस मामले में एनपीसी की जो भी कार्यक्षमता होनी चाहिए उसे लागू करने के लिए अपडेट फ़ंक्शन का विस्तार करें।

class build : component
{
  override void update()
  { 
    // Check if the right object is selected, resources, etc
  }
}

एक घटक कंटेनर Iterating और प्रत्येक घटक को अद्यतन करने से प्रत्येक घटक की विशिष्ट कार्यक्षमता को लागू करने की अनुमति मिलती है।

class npc
{
  void update()
  {
    foreach(component c in components)
      c.update();
  }

  list<component> components;
}

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

npc worker;
worker.add_component<build>();
worker.add_component<walk>();
worker.add_component<attack>();

मैं हमेशा समस्याओं में चला गया हूं क्योंकि घटक अधिक से अधिक जटिल हो जाते हैं। घटक की जटिलता को कम रखने (एक जिम्मेदारी) से उस समस्या को कम करने में मदद मिल सकती है।


3

यदि आप इंटरफेस को परिभाषित करते हैं, ICanBuildतो आपके गेम सिस्टम को हर एनपीसी का निरीक्षण करना होता है, जो आमतौर पर ओओपी में होता है। उदाहरण के लिए if (npc is ICanBuild):।

आप के साथ बेहतर कर रहे हैं:

interface INPC
{
    bool CanBuild { get; }
    void Build(...);
    bool CanFarm { get; }
    void Farm(...);
    ... etc.
}

फिर:

class Worker : INPC
{
    private readonly IBuildStrategy buildStrategy;
    public Worker(IBuildStrategy buildStrategy)
    {
        this.buildStrategy = buildStrategy;
    }

    public bool CanBuild { get { return true; } }
    public void Build(...)
    {
        this.buildStrategy.Build(...);
    }
}

... या निश्चित रूप से आप कई विभिन्न आर्किटेक्चर का उपयोग कर सकते हैं, जैसे कि धाराप्रवाह इंटरफ़ेस के रूप में कुछ प्रकार की डोमेन विशिष्ट भाषा, विभिन्न प्रकार के एनपीसी को परिभाषित करने के लिए, आदि, जहां आप विभिन्न व्यवहारों को जोड़कर एनपीसी प्रकार का निर्माण करते हैं:

var workerType = NPC.Builder
    .Builds(new WorkerBuildBehavior())
    .Farms(new WorkerFarmBehavior())
    .Build();

var workerFactory = new NPCFactory(workerType);

var worker = workerFactory.Build();

एनपीसी बिल्डर DefaultWalkBehaviorएक एनपीसी के मामले में ओवरराइड किया जा सकता है जो उड़ सकता है लेकिन उड़ नहीं सकता, आदि।


खैर, बस फिर से जोर से सोच: वास्तव में if(npc is ICanBuild)और के बीच बहुत अंतर नहीं है if(npc.CanBuild)। यहां तक ​​कि जब मैं npc.CanBuildअपने वर्तमान रवैये से रास्ता पसंद करूंगा ।
ब्रेटेटेट

3
@Brettetete - आप इस सवाल में देख सकते हैं कि कुछ प्रोग्रामर वास्तव में टाइप का निरीक्षण करना क्यों पसंद करते हैं।
स्कॉट व्हिटलॉक

0

मैं सभी क्षमताओं को अलग-अलग वर्गों में रखूँगा जो योग्यता से विरासत में मिली हैं। फिर यूनिट प्रकार वर्ग में क्षमताओं और अन्य सामानों की एक सूची होती है जैसे कि हमला, रक्षा, अधिकतम स्वास्थ्य आदि। एक इकाई वर्ग भी होता है जिसमें वर्तमान स्वास्थ्य, स्थान आदि होते हैं और एक सदस्य चर के रूप में इकाई प्रकार होता है।

हार्ड कोडिंग के बजाय सभी यूनिट प्रकारों को एक कॉन्फ़िगर फ़ाइल या डेटाबेस में परिभाषित करें।

तब स्तर डिजाइनर आसानी से खेल को फिर से शुरू किए बिना इकाई प्रकारों की क्षमताओं और आंकड़ों को समायोजित कर सकते हैं, और लोग खेल के लिए मॉड भी लिख सकते हैं।

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