कोई गलियारे और कमरे पर निर्भरता के साथ कालकोठरी पीढ़ी


15

मैं खेल की शुरुआत में एक प्रक्रियात्मक रूप से उत्पन्न दुनिया के साथ एक खेल बना रहा हूं, जिसमें ग्रिड द्वारा दर्शाए गए कई क्षेत्रों से मिलकर बनता है (जैसे, 8x8, 9x6, आकार आदर्श रूप से मनमाना होगा)। इन क्षेत्रों को एक निर्भरता सूची के माध्यम से एक दूसरे से जोड़ा जाना चाहिए।

एक कनेक्शन मौजूद है जब उन दो क्षेत्रों के बीच उस ग्रिड के कम से कम 3 स्थान उजागर होते हैं। उस 3 अंतरिक्ष कनेक्शन क्षेत्र के मध्य सेल में क्षेत्रों के बीच का द्वार है:

मैं उन्हें जोड़ने का एक तरीका निकालने की कोशिश कर रहा हूं, लेकिन यह उतना ही जटिल होता जा रहा है, जितने अधिक क्षेत्रों में आपको एक ही समय में विचार करने की आवश्यकता है।

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

यहाँ एक "सरल" उदाहरण है जो मैं अभी संघर्ष कर रहा हूँ:

  • क्षेत्र 'ए' को 'बी' और 'सी' से जोड़ने की जरूरत है
  • क्षेत्र 'बी' को 'ए' और 'डी' से जोड़ने की जरूरत है
  • क्षेत्र 'c' को 'a' और 'd' से जोड़ने की आवश्यकता है
  • क्षेत्र 'd' को 'b' और 'c' से जोड़ना होगा

विचार करें, सादगी के लिए, हम सूची में उनकी उपस्थिति के क्रम से कमरे रख रहे हैं (मैंने दूसरों की कोशिश की है)। तो मैं इसे आपके मानक प्रक्रियात्मक कालकोठरी पीढ़ी एल्गोरिथ्म के रूप में देख रहा हूं।

हम 'a' को बोर्ड पर कहीं भी रखते हैं, क्योंकि यह पहला क्षेत्र है। अगला, हम एक दीवार को यादृच्छिक रूप से चुनते हैं और, चूंकि कुछ भी उस दीवार से जुड़ा नहीं है, हम वहां 'बी' रख सकते हैं:

अब हमें 'सी' लगाने की आवश्यकता है, लेकिन 'ए' पहले से ही बोर्ड पर है, और एक अधिकृत दीवार है, इसलिए हम इसे दूसरी दीवार पर लगाने का फैसला करते हैं। लेकिन हर प्लेसमेंट ऐसा नहीं करेगा, क्योंकि 'd' सामने आ रहा है और इसे 'b' और 'c' से कनेक्ट करना होगा:

मैंने एक संभावित सीमा की कोशिश की कि 2 कमरे जिसमें निर्भरता का एक ही सेट है विपरीत दीवारों पर नहीं हो सकता है, लेकिन यहां तक ​​कि सफलता की गारंटी नहीं है:

और अन्य मामलों में, जहां क्षेत्रों के अलग-अलग आकार हैं, विपरीत दीवारों पर होना काम कर सकता है:

इसके अलावा, उपयोग की गई दीवार पर विचार न करना एक त्रुटिपूर्ण धारणा है क्योंकि यह वैध समाधानों को नियंत्रित करती है:

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

मैंने दृष्टिकोणों के एक समूह के बारे में सोचा, जिसमें एक क्षेत्र और बैकट्रैक शामिल है, जब तक कि एक उपयुक्त प्लेसमेंट नहीं मिला है, लेकिन वे परीक्षण और त्रुटि पर निर्भर हैं और गणना के मामले में महंगे हैं। लेकिन, मेरे द्वारा बताई गई अंतिम दो समस्याओं पर व्यापक शोध को देखते हुए, यह एकमात्र / सर्वोत्तम समाधान हो सकता है?

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


कमरे पूरी तरह से चौकोर होने चाहिए?
AturSams

यदि आपका मतलब है कि उनके पास 4 दीवारें हैं और अधिक नहीं तो हाँ, लेकिन मैंने ऐसा किया था कि दुनिया की जगह को सरल बनाया जाए। मुझे आसानी से उस स्थान की गणना करने की आवश्यकता है जो प्रत्येक क्षेत्र में व्याप्त है इसलिए मुझे पता है कि क्या मैं उस पर अपना सब कुछ डाल सकूंगा।
जोआना अल्मेडा

जवाबों:


6

यह एक ठंडी समस्या है। मेरा मानना ​​है कि कमरे के प्लेसमेंट के स्थान में एक्शन प्लानिंग का उपयोग करके इसे हल किया जा सकता है।

परिभाषित राज्य के रूप में इस दुनिया की:

//State:
//    A list of room states.
//    Room state:
//      - Does room exist?
//      - Where is room's location?
//      - What is the room's size?

एक बाधा को परिभाषित करें :

 // Constraint(<1>, <2>):
 //  - If room <1> and <2> exist, Room <1> is adjacent to Room <2>

जहां "आसन्न" आप के रूप में वर्णित है (कम से कम 3 पड़ोसियों को साझा करना)

जब भी दो कमरे सटे हुए नहीं हैं , और दोनों कमरे मौजूद हैं, तो एक बाधा को अमान्य कहा जाता है।

एक परिभाषित राज्य होने के लिए वैध होता है:

// foreach Constraint:
//        The Constraint is "not invalidated".
// foreach Room:
//       The room does not intersect another room.

वर्तमान स्थिति को देखते हुए एक कार्य को एक कमरे के स्थान के रूप में परिभाषित करें । कार्रवाई है वैध जब भी कार्रवाई से उत्पन्न स्थिति मान्य है। इसलिए, हम प्रत्येक राज्य के कार्यों की एक सूची तैयार कर सकते हैं:

// Returns a list of valid actions from the current state
function List<Action> GetValidActions(State current, List<Constraint> constraints):
    List<Action> actions = new List<Action>();
    // For each non-existent room..
    foreach Room room in current.Rooms:
        if(!room.Exists)
            // Try to put it at every possible location
            foreach Position position in Dungeon:
                 State next = current.PlaceRoom(room, position)
                 // If the next state is valid, we add that action to the list.
                 if(next.IsValid(constraints))
                     actions.Add(new Action(room, position));

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

// Given a start state (with all rooms set to *not exist*), and a set of
// constraints, finds a valid end state where all the constraints are met,
// using a depth-first search.
// Notice that this gives you the power to pre-define the starting conditions
// of the search, to for instance define some key areas of your dungeon by hand.
function State GetFinalState(State start, List<Constraint> constraints)
    Stack<State> stateStack = new Stack<State>();
    State current = start;
    stateStack.push(start);
    while not stateStack.IsEmpty():
        current = stateStack.pop();
        // Consider a new state to expand from.
        if not current.checked:
            current.checked = true;
            // If the state meets all the constraints, we found a solution!
            if(current.IsValid(constraints) and current.AllRoomsExist()):
                return current;

            // Otherwise, get all the valid actions
            List<Action> actions = GetValidActions(current, constraints);

            // Add the resulting state to the stack.
            foreach Action action in actions:
                State next = current.PlaceRoom(action.room, action.position);
                stateStack.push(next);

    // If the stack is completely empty, there is no solution!
    return NO_SOLUTION;

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


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

7

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

सामान्य एल्गोरिथम

  1. 2 डी सरणी या छवि का उपयोग करके, अपने स्तर का समर्थन करने के लिए पर्याप्त आकार का एक निर्धारित मंजिल ग्रिड बनाएं।

  2. इस खाली मंजिल में यादृच्छिक बिंदु पर स्कैटर। आप प्रत्येक टाइल पर एक सादा यादृच्छिक जांच का उपयोग करके देख सकते हैं कि क्या यह एक बिंदु मिलता है, या तितर बितर करने के लिए मानक / गाऊसी वितरण का उपयोग करें। प्रत्येक और हर बिंदु के लिए एक अद्वितीय रंग / संख्यात्मक मान असाइन करें। ये आईडी हैं। (पुनश्च अगर इस कदम के बाद आपको लगता है कि आपको अपने अंतरिक्ष को बड़े पैमाने पर करने की आवश्यकता है, तो हर तरह से।)

  3. इस तरह के प्रत्येक उत्पन्न बिंदु के लिए, क्रम में, एक कदम से (आमतौर पर 0.5-1.0 कोशिकाओं / पिक्सल प्रति चरण की दर) एक सीमा से बाहर एक सीमा चक्र या सीमा आयत बढ़ते हैं। x और y। आप या तो समानांतर में सभी सीमाएँ विकसित कर सकते हैं, सभी एक ही चरण में आकार शून्य से शुरू हो सकते हैं, या आप उन्हें अलग-अलग समय पर और अलग-अलग दरों पर बढ़ाना शुरू कर सकते हैं, जो पहले शुरू होने वाले आकार को पूर्वाग्रह देते हैं (अंकुर बढ़ने की कल्पना करें, जहां कुछ देर से शुरू)। "बढ़ने" से मेरा मतलब है कि उन सीमाओं के लिए शुरुआती बिंदु के लिए अद्वितीय रंग / आईडी के साथ नए-बढ़े हुए सीमा में भरें। इसके लिए एक रूपक कागज के एक टुकड़े के पीछे मार्कर पेन को पकड़े हुए होगा, और जब तक वे मिलते हैं, तब तक अलग-अलग रंगों के इंकबोल्ट बढ़ते हुए देखते हैं।

  4. कुछ बिंदु पर कुछ बिंदु की सीमा और एक अन्य बिंदु बढ़ते कदम के दौरान टकराते जा रहे हैं। यह वह बिंदु है जिस पर आपको उन दो बिंदुओं के लिए सीमा को बढ़ाना बंद कर देना चाहिए - कम से कम चरण 3 में वर्णित समान अर्थों में।

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

पोस्ट-प्रोसेस स्पेस-फिलिंग

विभिन्न प्रकार की तकनीकों का उपयोग रिक्त / सफेद रिक्त स्थान को भरने के लिए किया जा सकता है, जो कि चरण 5 में है:

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

गड़बड़ी

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

रुचि के लिए सिद्धांत

यह वोरोनोई डायग्राम्स / डेलॉने ट्राइंगुलेशन में लिए गए दृष्टिकोण के समान है , सिवाय इसके कि ऊपर आप स्पष्ट रूप से किनारों का निर्माण नहीं कर रहे हैं - इसके बजाय, जब बाउंडिंग क्षेत्र टकराते हैं, तो विकास बंद हो जाता है। आप ध्यान देंगे कि वोरोनोई डायग्राम कार्ड-फिलिंग हैं; इसका कारण यह है कि वे केवल छूने पर विकास को रोकते नहीं हैं, बल्कि ओवरलैप के कुछ नाममात्र डिग्री पर हैं। आप इसी तरह की कोशिश कर सकते हैं।

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