अपने पूरे कोड में झंडे और जांच से बचने के लिए मैं क्या कर सकता हूं?


18

एक कार्ड गेम पर विचार करें, जैसे कि हार्टस्टोन

ऐसे सैकड़ों कार्ड हैं जो कई प्रकार की चीजें करते हैं, जिनमें से कुछ एकल कार्ड के लिए भी अद्वितीय हैं! उदाहरण के लिए, एक कार्ड है (जिसे नोज़डॉर्मु कहा जाता है) जो खिलाड़ी को केवल 15 सेकंड में बदल देता है!

जब आपके पास संभावित प्रभावों की इतनी विस्तृत विविधता है, तो आप अपने कोड पर मैजिक नंबर और वन-ऑफ चेक से कैसे बच सकते हैं? प्लेयरटर्नटाइम क्लास में एक "Check_Nozdormu_In_Play" विधि से कैसे बचा जा सकता है? और कोई ऐसे कोड को कैसे व्यवस्थित कर सकता है कि जब आप और भी अधिक प्रभाव जोड़ते हैं , तो आपको उन सामानों का समर्थन करने के लिए कोर सिस्टम को रिफलेक्टर करने की आवश्यकता नहीं होती है जो उन्हें पहले कभी समर्थन नहीं करना पड़ा है?


क्या यह वास्तव में एक प्रदर्शन समस्या है? मेरा मतलब है, आप लगभग कुछ ही समय में आधुनिक सीपीयू के साथ पागल राशि का सामान कर सकते हैं ..
जरी कोमप्पा

11
प्रदर्शन समस्याओं के बारे में कुछ भी किसने कहा? मेरे द्वारा देखी जाने वाली मुख्य समस्या यह है कि जब भी आप नया कार्ड बनाते हैं, तो आपको अपने सभी कोड को समायोजित करने की निरंतर आवश्यकता होती है।
झॉकिंग

2
इसलिए प्रत्येक कार्ड में एक स्क्रिप्टिंग भाषा और स्क्रिप्ट जोड़ें।
जरी कोमप्पा

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

2
कुछ बिंदु पर मैं आश्चर्य करने के लिए है, तो कोड के प्रासंगिक बिट पर तदर्थ चेकों जोड़ने है आसान समाधान।
user253751

जवाबों:


12

क्या आपने इकाई घटक सिस्टम और ईवेंट मैसेजिंग रणनीतियों में देखा है?

स्थिति प्रभाव कुछ प्रकार के घटक होने चाहिए जो एक OnCreate () विधि में उनके लगातार प्रभाव को लागू कर सकते हैं, OnRemoved () में उनके प्रभावों को समाप्त कर सकते हैं और कुछ होने वाली प्रतिक्रिया के रूप में होने वाले प्रभावों को लागू करने के लिए गेम इवेंट संदेशों की सदस्यता ले सकते हैं।

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

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

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


2
"सुनिश्चित करें कि जो कुछ भी बदला जा सकता है वह एक डेटा चालित वैरिएबल है जो किसी भी अपवाद के लिए उपयोग किए जाने वाले चरों के साथ हार्ड कोडित चूक के बजाय एक डेटा संचालित चर है।" - ऊह, मुझे काफी पसंद है। मुझे लगता है कि बहुत मदद करता है!
सेबल ड्रीमर

क्या आप "उनके लगातार प्रभावों को लागू करने" पर विस्तार से बता सकते हैं? टर्नस्टार्ट में सब्सक्राइब नहीं करना चाहिए और फिर लंबाई का मान बदलना कोड को अपरिहार्य बना देगा और या इससे भी बदतर असंगत परिणाम उत्पन्न करेगा (जब समान प्रभावों के बीच बातचीत हो)?
५२

केवल उन ग्राहकों के लिए जो किसी भी समय अवधि को मान लेंगे। आपको ध्यान से मॉडलिंग करनी होगी। यह अच्छा हो सकता है कि चालू टर्न टाइम खिलाड़ी के टर्न टाइम से अलग हो। एक नया मोड़ बनाने के लिए PTT की जाँच की जाएगी। सीटीटी कार्ड द्वारा जाँच की जा सकती है। यदि किसी प्रभाव को वर्तमान समय में वृद्धि करनी चाहिए, तो टाइमर यूआई को स्वाभाविक रूप से सूट का पालन करना चाहिए यदि वह स्टेटलेस है।
रॉबस्टोन

प्रश्न का बेहतर उत्तर देने के लिए। कुछ भी नहीं है कि बंद समय या कुछ भी बंद संग्रहीत करता है। हमेशा इसके लिए जाँच करें।
रॉबस्टोन

11

रॉबस्टोन सही रास्ते पर है, लेकिन मैं विस्तार से जानना चाहता था क्योंकि मैंने डंगऑन हो को ऐसा ही लिखा था !, एक रोजुलाइक जिसमें हथियारों और मंत्रों के लिए एक बहुत ही जटिल प्रभाव प्रणाली थी।

प्रत्येक कार्ड में इसके साथ संलग्न प्रभावों का एक सेट होना चाहिए, इसे इस तरह से परिभाषित किया जाए कि यह इंगित कर सके कि यह प्रभाव क्या है, यह क्या लक्ष्य रखता है, कैसे, और कितने समय तक। उदाहरण के लिए, "प्रतिद्वंद्वी को नुकसान" प्रभाव कुछ इस तरह दिखाई दे सकता है;

Effect type: deal damage (enumeration, string, what-have-you)
Effect amount: 20
Source: my weapon
Target: opponent
Effect Cost: 20
Cost Type: Mana

फिर, जब प्रभाव में आग लग जाती है, तो एक सामान्य दिनचर्या प्रभाव के प्रसंस्करण को संभालती है। एक बेवकूफ की तरह, मैंने एक बड़ा मामला / स्विच स्टेटमेंट का उपयोग किया:

switch (effect_type)
{
     case DAMAGE:

     break;
}

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

class Effect
{
    Object source;
    int amount;

    public void onExecute(Object target)
    {
          // Do nothing
    }
}

class DamageEffect extends Effect
{
    public void onExecute(Object target)
    {
          target.health -= amount;
    }
}

इसलिए हमारे पास एक बेसिक इफेक्ट क्लास होगा, फिर एक ऑनएज्यूट () पद्धति के साथ डैमेजफैक्ट क्लास, इसलिए हमारे प्रोसेसिंग कोड में हम बस जाएंगे;

Effect effect = card.getActiveEffect();

effect.onExecute();

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

Effect effect;

for (int o = 0; o < objects.length; o++)
{
    for (int e = 0; e < objects[o].effects.length; e++)
    {
         effect = objects[o].effects[e];

         effect.onExecute();
    }
}

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

1

मैं कुछ सुझाव सुझाता हूँ। उनमें से कुछ एक-दूसरे का खंडन करते हैं। लेकिन शायद कुछ उपयोगी हैं।

सूचियों बनाम झंडे पर विचार करें

आप दुनिया भर में पुनरावृत्ति कर सकते हैं और प्रत्येक आइटम पर एक ध्वज की जांच कर सकते हैं ताकि यह तय किया जा सके कि झंडा-चीज़ क्या करना है। या आप केवल उन वस्तुओं की एक सूची रख सकते हैं जिन्हें ध्वज-वस्तु करना चाहिए।

सूचियों और गणना पर विचार करें

आप अपने आइटम वर्ग, isAThis और isAThat में बूलियन फ़ील्ड जोड़ सकते हैं। या आपके पास स्ट्रिंग्स या एनम तत्वों की सूची हो सकती है, जैसे {"isAThis", "isAThat"} या {IS_A_THIS, IS_A_THAT}। इस तरह से आप फ़ील्ड्स को जोड़े बिना एन्यूमरेशन (या स्ट्रिंग कॉन्स्ट) में नए जोड़ सकते हैं। ऐसा नहीं है कि खेतों को जोड़ने के साथ वास्तव में कुछ भी गलत है ...

फ़ंक्शन पॉइंटर्स पर विचार करें

झंडे या एनम की सूची के बजाय, विभिन्न संदर्भों में उस आइटम को निष्पादित करने के लिए कार्यों की एक सूची हो सकती है। (इकाई-इश ...)

वस्तुओं पर विचार करें

कुछ लोग डेटा-चालित, या स्क्रिप्टेड, या घटक निकाय दृष्टिकोण पसंद करते हैं। लेकिन पुराने जमाने की वस्तुएं पदानुक्रम भी विचार करने लायक हैं। आधार वर्ग को क्रियाओं को स्वीकार करने की आवश्यकता है, जैसे "टर्न-फेज बी के लिए यह कार्ड खेलें" या जो भी हो। तब प्रत्येक प्रकार का कार्ड ओवरराइड कर सकता है और उचित प्रतिक्रिया दे सकता है। वहाँ शायद एक खिलाड़ी वस्तु और खेल वस्तु के रूप में अच्छी तरह से है, तो खेल की तरह चीजें कर सकते हैं, अगर (खिलाड़ी- isAllowedToPlay ()) {नाटक करें…}।

डिबग-क्षमता पर विचार करें

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

आखिरकार, रिफैक्टिंग: इकाई परीक्षणों पर विचार करें

कोई फर्क नहीं पड़ता कि आप अपनी वास्तुकला को कितना सामान्य करते हैं, आप उन चीजों की कल्पना करने में सक्षम होंगे जो इसे कवर नहीं करती हैं। फिर आपको रिफलेक्टर करना होगा। शायद थोड़ा, शायद बहुत।

इस सुरक्षित बनाने का एक तरीका इकाई परीक्षणों के एक निकाय के साथ है। इस तरह आप आश्वस्त हो सकते हैं कि भले ही आपने चीजों को फिर से व्यवस्थित किया हो (शायद बहुत से!) मौजूदा कार्यक्षमता अभी भी काम करती है। प्रत्येक इकाई परीक्षण आम तौर पर इस तरह दिखता है:

void test1()
{
   Game game;
   game.addThis();
   game.setupThat(); // use primary or backdoor API to get game to known state

   game.playCard(something something).

   int x = game.getSomeInternalState;
   assertEquals(“did it do what we wanted?”, x, 23); // fail if x isn’t 23
}

जैसा कि आप देख सकते हैं, खेल (या खिलाड़ी, कार्ड, और ग) पर उन शीर्ष-स्तरीय एपीआई कॉल को स्थिर रखना इकाई परीक्षण रणनीति की कुंजी है।


0

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

यह अनिवार्य रूप से एक मिनी-घटक प्रणाली है, जहां प्रत्येक "कार्ड" ऑब्जेक्ट बस प्रभाव घटकों के एक समूह के लिए एक कंटेनर है।


चूंकि कार्ड - और भविष्य के कार्ड भी - बस कुछ भी कर सकते हैं, मुझे उम्मीद है कि प्रत्येक कार्ड एक स्क्रिप्ट को ले जाएगा। फिर भी मुझे पूरा यकीन है कि यह एक वास्तविक प्रदर्शन समस्या नहीं है ..
जरी कोमप्पा

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