एक साधारण साहसिक खेल में व्यवहार को लागू करना


11

मैं एक सरल पाठ-आधारित साहसिक खेल की प्रोग्रामिंग करके हाल ही में अपने आप को मनोरंजन कर रहा हूं, और मैं एक बहुत ही सरल डिजाइन मुद्दे की तरह लगता है।

एक संक्षिप्त अवलोकन देने के लिए: खेल Roomवस्तुओं में टूट गया है। प्रत्येक में Roomउन Entityवस्तुओं की एक सूची है जो उस कमरे में हैं। प्रत्येक Entityमें एक घटना अवस्था होती है, जो एक साधारण स्ट्रिंग-> बूलियन मैप और एक एक्शन लिस्ट होती है, जो एक स्ट्रिंग-> फ़ंक्शन मैप होती है।

उपयोगकर्ता इनपुट का रूप लेता है [action] [entity]Roomउपयुक्त Entityवस्तु को वापस करने के लिए इकाई नाम का उपयोग करता है , जो तब सही फ़ंक्शन को खोजने के लिए क्रिया नाम का उपयोग करता है, और इसे निष्पादित करता है।

कमरे के विवरण को उत्पन्न करने के लिए, प्रत्येक Roomऑब्जेक्ट अपना विवरण स्ट्रिंग प्रदर्शित करता है, फिर हर के विवरण तार को जोड़ता है EntityEntityवर्णन अपने राज्य के आधार पर बदल सकता है ( "दरवाजा खुला है", "दरवाज़ा बंद है", आदि "दरवाजा बंद कर दिया है")।

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

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

संपादित 1: जैसा कि अनुरोध किया गया है, इन कार्रवाई कार्यों के छद्म कोड उदाहरण हैं।

string outsideDungeonBushesSearch(currentRoom, thisEntity, player)
    if thisEntity["is_searched"] then
        return "There was nothing more in the bushes."
    else
        thisEntity["is_searched"] := true
        currentRoom.setEntity("dungeonDoorKey")
        return "You found a key in the bushes."
    end if

string dungeonDoorKeyUse(currentRoom, thisEntity, player)
    if getEntity("outsideDungeonDoor")["is_locked"] then
        getEntity("outsideDungeonDoor")["is_locked"] := false
        return "You unlocked the door."
    else
        return "The door is already unlocked."
    end if

विवरण फ़ंक्शन बहुत हद तक उसी तरह से कार्य करते हैं, राज्य की जाँच करते हैं और उपयुक्त स्ट्रिंग लौटाते हैं।

EDIT 2: मेरे प्रश्न को संशोधित किया। मान लें कि इन-गेम ऑब्जेक्ट्स की एक महत्वपूर्ण संख्या हो सकती है जो अन्य व्यवहारों के साथ सामान्य व्यवहार (विशिष्ट कार्यों के लिए राज्य-आधारित प्रतिक्रिया) को साझा नहीं करते हैं। क्या कोई तरीका है जो मैं इन अद्वितीय व्यवहारों को एक क्लीनर में परिभाषित कर सकता हूं, प्रत्येक इकाई-विशिष्ट कार्रवाई के लिए कस्टम फ़ंक्शन लिखने की तुलना में अधिक बनाए रखने योग्य तरीका है?


1
मुझे लगता है कि आपको यह समझाने की ज़रूरत है कि ये "एक्शन फ़ंक्शंस" क्या करते हैं और शायद कुछ कोड पोस्ट करते हैं, क्योंकि मुझे यकीन नहीं है कि आप वहां क्या बात कर रहे हैं।
1

कोड जोड़ा गया।
एरिक

जवाबों:


5

संज्ञा और क्रिया के हर संयोजन के लिए एक अलग फ़ंक्शन बनाने के बजाय, आपको एक आर्किटेक्चर सेटअप करना चाहिए जहां एक सामान्य इंटरफ़ेस है जिसे गेम में सभी ऑब्जेक्ट कार्यान्वित करते हैं।

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

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

इस बीच, सार्वजनिक तरीकों में से एक Entity.actOn (स्ट्रिंग कार्रवाई) की तरह कुछ है तो उस विधि में उस वस्तु के लिए कार्रवाई की तालिका के साथ पारित कार्रवाई की तुलना करें; यदि वह कार्रवाई तालिका में है, तो परिणाम वापस करें।

अब प्रत्येक ऑब्जेक्ट के लिए आवश्यक सभी अलग-अलग फ़ंक्शन ऑब्जेक्ट के भीतर समाहित हो जाएंगे, जिससे उस ऑब्जेक्ट को अन्य कमरों में दोहराना आसान हो जाता है (जैसे कि हर कमरे में एक डोर ऑब्जेक्ट को इंस्टेंट करना जिसमें दरवाजा है)

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

<rooms>
  <room id="room1">
    <description>Outside the dungeon you see some bushes and a heavy door over the entrance.</description>
    <entities>
      <bush>
        <description>The bushes are thick and leafy.</description>
        <contains>
          <key />
        </contains>
      </bush>
      <door connection="room2" isLocked="true">
        <description>It's an oak door with stout iron clasps.</description>
      </door>
    </entities>
  </room>

  <room id="room2">
    etc.

ADDITION: अहा, मैंने अभी-अभी FxIII का उत्तर पढ़ा है और अंत के पास इस बिट ने मुझे बाहर निकाला:

(no things like <item triggerFlamesOnPicking="true"> that you will use just once)

यद्यपि मैं असहमत हूं कि एक लौ ट्रैप को ट्रिगर किया जा रहा है, जो केवल एक बार होगा (मैं इस जाल को कई अलग-अलग वस्तुओं के लिए पुन: उपयोग किया जा सकता है) मुझे लगता है कि मुझे अंत में मिलेगा कि आप उन संस्थाओं के बारे में क्या कहते हैं जो उपयोगकर्ता इनपुट के लिए विशिष्ट रूप से प्रतिक्रिया करते हैं। मैं शायद अपने तहखाने में एक दरवाजा बनाने जैसे सामान को संबोधित करूंगा, मेरे सभी इकाइयों को एक घटक वास्तुकला (अन्यत्र विस्तार से समझाया गया है) के साथ निर्माण करके एक आग का गोला है।

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

<entity name="door">
  <description>It's an oak door with stout iron clasps.</description>
  <components>
    <lock isLocked="true" />
    <portal connection="room2" />
  </components>
</entity>

लेकिन आग के गोले के साथ एक दरवाजा होगा

<entity name="door">
  <description>There are strange runes etched into the wood.</description>
  <components>
    <lock isLocked="true" />
    <portal connection="room7" />
    <fireballTrap />
  </components>
</entity>

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

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

Door extends Entity {
  public Door() {
    addComponent(new LockComponent());
    addComponent(new PortalComponent());
  }
}

TrappedDoor extends Entity {
  public TrappedDoor() {
    addComponent(new LockComponent());
    addComponent(new PortalComponent());
    addComponent(new FireballTrap());
  }
}

1
यह आम, दोहराने योग्य वस्तुओं के लिए काम करता है। लेकिन उन संस्थाओं के बारे में जो उपयोगकर्ता इनपुट के लिए विशिष्ट रूप से प्रतिक्रिया देते हैं? Entityएक ही वस्तु समूहों के लिए कोड को एक साथ उप-वर्ग बनाना, लेकिन मुझे जो कोड लिखना है उसे कम नहीं करना है। या कि इस संबंध में एक अपरिहार्य नुकसान है?
एरिक

1
मैंने आपके द्वारा दिए गए उदाहरणों को संबोधित किया। मैं आपका मन नहीं पढ़ सकता; क्या वस्तुओं और आदानों आप करना चाहते हैं?
३२:२२

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

हाँ, यह विचार है।
jhocking

मुझे लगा होगा कि घटक समाधान का हिस्सा रहे होंगे। सहायता के लिए धन्यवाद।
एरिक

1

आपके द्वारा संबोधित आयामी समस्या काफी सामान्य है और लगभग अपरिहार्य है। आप अपनी संस्थाओं को व्यक्त करने के लिए एक रास्ता खोजना चाहते हैं जो कि संयोग और लचीला दोनों है

एक "कंटेनर" (झॉकिंग जवाब में झाड़ी) एक संयोग तरीका है लेकिन आप देखते हैं कि यह पर्याप्त लचीला नहीं है।

मैं आपको सुझाव नहीं देता कि आप एक सामान्य इंटरफ़ेस खोजने की कोशिश करें और फिर व्यवहार को निर्दिष्ट करने के लिए कॉन्फ़िगरेशन फ़ाइलों का उपयोग करें, क्योंकि आपके पास हमेशा एक रॉक (मानक और उबाऊ संस्थाओं, वर्णन करने में आसान) और एक कठिन स्थान के बीच होने के लिए अप्रिय उत्तेजना होगी ( अद्वितीय शानदार इकाइयां लेकिन लागू करने के लिए बहुत लंबा)।

मेरा सुझाव कोड व्यवहार के लिए एक व्याख्या की गई भाषा का उपयोग करना है।

बुश उदाहरण के बारे में सोचें: यह एक कंटेनर है, लेकिन हमारे बुश को भीतर विशिष्ट वस्तुओं की आवश्यकता है; कंटेनर वस्तु हो सकती है:

  • आइटम जोड़ने के लिए कहानीकार के लिए एक विधि,
  • इंजन में आइटम को दिखाने के लिए एक विधि है,
  • एक आइटम लेने के लिए खिलाड़ी के लिए एक विधि।

कुछ वस्तुओं में से एक में एक रस्सी होती है जो एक गर्भनिरोधक को ट्रिगर करती है जो बदले में झाड़ी को जलाने वाली एक लौ को आग लगाती है ... (आप देखें, मैं आपके दिमाग को पढ़ सकता हूं इसलिए मुझे आपके पसंद के सामान पता है)।

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

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

सभी इकाइयां स्क्रिप्ट के लिए सुलभ होनी चाहिए: आप प्रत्येक इकाई के लिए एक पहचानकर्ता को जोड़ सकते हैं और उन्हें एक कंटेनर में रख सकते हैं जो स्क्रिप्टिंग भाषा स्क्रिप्ट के विस्तार में निर्यात किया जाता है।

स्क्रिप्टिंग रणनीतियों का उपयोग करना आपको अपने कॉन्फ़िगरेशन को सरल रखने की अनुमति देता है (कोई भी चीज़ <item triggerFlamesOnPicking="true">जो आप बस एक बार उपयोग करेंगे), जबकि आप विषम बीवीओ को व्यक्त करने की अनुमति देते हैं (मजेदार वाले) कोड की कुछ पंक्ति जोड़ते हुए

कुछ शब्दों में: कॉन्फ़िगर फाइल के रूप में स्क्रिप्ट जो कोड चला सकती है।

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