
एक प्रमुख गेम डेवलपर क्या करता है जब उसे खेल की दुनिया के लिए बहुत सारे स्थान बनाने की आवश्यकता होती है? कलाकारों का एक समूह काम पर रखता है। एक ही स्थिति में एक आलसी / गरीब / अकेला गेम डेवलपर क्या करता है? वह एक प्रक्रियात्मक जनरेटर लिखता है जो उसके लिए सभी गंदे काम करता है।
फर्श योजनाओं की प्रक्रियात्मक पीढ़ी पर
कई ,
कई लेख हैं ।
यहां लेखों के पांच और लिंक दिए गए हैं । केवल स्रोत कोड उनमें से कोई भी नहीं है।
इस लेख में मैं बात करूंगा कि कैसे मैंने यूनिटी 3 डी एक सरल पीढ़ी पद्धति पर लागू किया, जिससे अच्छे परिणाम प्राप्त होते हैं और आसानी से संशोधित होते हैं। चित्रों और स्रोत कोड के साथ।
यदि आप चाहें, तो आप
मूल लेख पढ़ सकते हैं, लेकिन सार लगभग निम्नलिखित है:
- सभी जगहों को वास्तु योजनाओं में एक ग्रिड की तरह कोशिकाओं में विभाजित किया गया है।
- बाहरी दीवारें पहले से ही मौजूद हैं और कार्यक्रम के प्रवेश द्वार में खिलाया जाता है।
- कमरों की एक सूची है जिसे योजना पर रखा जाना चाहिए।
- कमरों में पैरामीटर "वांछित आकार" और एक दूसरे के लिए आकर्षण के गुणांक हैं
- कमरों के जन्म के बिंदु योजना के अनुसार यादृच्छिक रूप से बिखरे हुए हैं, संभवतः कुछ अनुमानित नक्शे की मदद से।
- तब प्रत्येक बिंदु आयताकार रूप से बढ़ने लगता है जब तक कि वह इसके लिए निर्धारित आयामों तक नहीं पहुंचता।
- जब सभी आयतें बढ़ गई हैं, तब तक अक्षर L के आकार में कमरे बढ़ने लगते हैं।
- शेष खाली स्थान को पड़ोसियों को दिया जाता है।
कमरे एक-दूसरे के ऊपर रेंगने वाली दीवारों और कमरों से बचने के लिए एक समय में एक दीवार विकसित करते हैं। कमरे की सबसे बड़ी दीवारों से दीवार का चयन किया जाता है, यदि समान हैं, तो एक यादृच्छिक लिया जाता है। सबसे बड़ी दीवार को लिया जाता है ताकि कमरों के क्षेत्र में वृद्धि अधिकतम हो, और वे "झोंके" हों।
अब मेरे कार्यान्वयन के बारे में। मैंने अब तक यथार्थवादी लेआउट, गुणांक और कमरों के आकार के साथ परेशान नहीं किया - ये सभी अलंकरण हैं, मैंने बुनियादी एल्गोरिथ्म पर काम किया, बाकी सब जल्दी से जोड़ा जा सकता है। इसके अलावा, लेख विशेष जांच के बारे में बात करता है जो यू-आकार के कमरों की उपस्थिति को रोकते हैं, मैंने उन्हें नहीं किया, मुझे ऐसे कमरों में कुछ भी बुरा नहीं दिखता है। इसके अलावा, मैंने गलियारों, दरवाजों और खिड़कियों की व्यवस्था नहीं की, यह एक अलग विषय है, और उनकी व्यवस्था बाकी इमारत की पीढ़ी पर निर्भर हो सकती है।
सबसे कठिन बात यह थी कि कमरे की वृद्धि के सिद्धांत और उनके और भवन के बारे में डेटा स्टोर करने का तरीका चुनना। एक ही परिणाम सेलुलर ऑटोमेटा या सरणी के माध्यम से एक साधारण रन का उपयोग करके भी प्राप्त किया जा सकता है। मैंने कई विकल्पों की कोशिश की, मैं हमेशा कमरे के आयामों और इसकी दीवारों की सटीक स्थिति के बारे में एक विचार रखना चाहता था, इसलिए मैंने एक वर्ग बनाया, जिसमें केवल कमरे के कोनों को संग्रहीत किया जाता है, और दीवारें दो आसन्न कोनों को जोड़कर स्वचालित रूप से बनाई जाती हैं।

दीवारों को जोड़ना अनिवार्य रूप से बिंदुओं के एक सेट से बहुभुज खोल की खोज है। कार्य तुच्छ नहीं है और चाल की एक गुच्छा के साथ, अगर दिलचस्पी है, तो मैं आपको
यहां देखने की सलाह देता हूं। सौभाग्य से, मैंने अपने आप को समीप की दीवारों के बीच समकोण बनाने का फैसला किया और एक सरल एल्गोरिथ्म बनाया:
- बिंदुओं के सेट में X और Y निर्देशांक का न्यूनतम और अधिकतम मान ज्ञात करें।
- बिंदु (minX, minY) से हम igruka पर जाते हैं और वैकल्पिक रूप से ऐसे निर्देशांक के साथ एक बिंदु की तलाश करते हैं, अगर यह वहां नहीं है, तो दाएं, नीचे और बाएं देखें। जब हम पाते हैं, हम इसे पुरानी सूची से बाहर निकाल देते हैं, इसे नई सूची में स्थानांतरित कर देते हैं।
- पुरानी सूची में इस बिंदु के निर्देशांक से, हम खेल में अगले बिंदु की तलाश करते हैं, अगर हम इसे ढूंढते हैं, तो हम इसे नई सूची में स्थानांतरित करते हैं, इसे पुरानी से हटा दें, याद रखें कि हमें एक दीवार मिली जो वाई के समानांतर है, इसलिए अगली दीवार एक्स के समानांतर होनी चाहिए।
- हम दाईं ओर और बाईं ओर एक्स द्वारा एक बिंदु की खोज करते हैं, एक नई सूची में स्थानांतरित करते हैं, हम अभी-अभी मिली हुई दीवार के उन्मुखीकरण को याद करते हैं, सादृश्य द्वारा आगे देखें।
- पुरानी सूची में अंतिम बिंदु बस नए में स्थानांतरित हो जाता है।
कमरे के कोनों को छाँटेंpublic GridVector SortCorners() {

अंत में, हमें घड़ी की दिशा में क्रमबद्ध कोणों की एक सूची मिलती है, जिससे आप आसानी से दीवारों को प्रदर्शित कर सकते हैं। छँटाई के लिए धन्यवाद, एक और महत्वपूर्ण बात सीखना आसान हो जाता है - कमरे की दीवार से बाहर की दिशा। दीवार के अंत को बाहर करने के लिए, आपको एक्स और वाई को स्वैप करना होगा और निम्नलिखित प्राप्त करने के लिए पहले समन्वय को उलटना होगा: (-y, x)।
कमरों को अंक के रूप में संग्रहीत किया जाता है, अंक सॉर्ट किए जाते हैं, दीवारों को स्वचालित रूप से बनाया जाता है, बाहरी दिशा ज्ञात होती है - यह सब फर्श की योजना पर खाली स्थान की जांच करने और कमरों को विकसित करने के लिए पर्याप्त है। कभी-कभी यह सच होता है कि आपको नई दीवारों को जोड़ना पड़ता है जब पुराने लोगों ने किसी चीज में आराम किया हो और बढ़ नहीं सकते।

कोशिकाओं की उपलब्धता की जांच करने और संभावित नई दीवारों की खोज करने के लिए, मैं एक फ़ंक्शन का उपयोग करता हूं, जो प्रवेश द्वार को आपूर्ति की गई दीवार के विकास खंडों के लिए उपलब्ध सूची को एकत्र करता है। तब मैं पूरे कमरे से श्रेणियों में पाए गए खंडों को छांटता हूं: ठोस दीवारें, दीवार के किनारे पर टुकड़े, केंद्रीय खंड। मैं उपलब्ध लोगों में से सबसे बड़ी दीवार का चयन करता हूं और इसे कमरे के विकास कार्य में भेजता हूं, और वह समझती है कि क्या उसके पास पहले से ही ऐसी दीवार है, या एक नया निर्माण करने की आवश्यकता है। जब एक दीवार होती है, तो इसके सिरों के निर्देशांक को बाहर की ओर स्थानांतरित किया जाता है, जिससे पड़ोसी दीवारों का स्वत: विस्तार होता है।
दीवार खंडों के लिए खोजें List<RoomWall> FindSegments(RoomWall wall, Color freeColor, Color roomColor) { var moved = wall + wall.outwards.minimized; BresenhamLine(moved, new Color(Random.value * 0.7f + 0.1f, Random.value * 0.7f + 0.1f, Random.value * 0.7f + 0.1f), segmentsTexture); var x0 = moved.start.x; var y0 = moved.start.y; var x1 = moved.end.x; var y1 = moved.end.y; var segments = new List<RoomWall>(); GridVector start = null; GridVector end = null; bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0); if (steep) { Swap(ref x0, ref y0); Swap(ref x1, ref y1); } if (x0 > x1) { Swap(ref x0, ref x1); Swap(ref y0, ref y1); } for (int x = x0; x <= x1; x++) { for (int y = y0; y <= y1; y++) { int coordX = steep ? y : x; int coordY = steep ? x : y; Color color = texture.GetPixel(coordX, coordY); if (color != freeColor && color != roomColor) { if (end != null && start != null) { var segment = new RoomWall(start, end); segment -= wall.outwards.minimized; segments.Add(segment); start = null; end = null; } scanTexture.SetPixel(coordX, coordY, Color.red); } else { if (start == null) { start = new GridVector(coordX, coordY); } end = new GridVector(coordX, coordY); scanTexture.SetPixel(coordX, coordY, Color.green); } } } if (end != null && start != null) { var segment = new RoomWall(start, end); segment -= wall.outwards.minimized; segments.Add(segment); } return segments; }
कमरों के साथ सभी जोड़तोड़ को प्रदर्शित करने के लिए, मैं एक बनावट का उपयोग करता हूं जिसमें पिक्सल मैं दीवारों की स्थिति में प्रवेश करता हूं। यदि आप पुरानी दीवारों को नहीं मिटाते हैं, तो आपको भरे हुए क्षेत्र मिलते हैं, जैसे लेख की शुरुआत में gif पर। मैं ब्रेशेनम लाइनों का उपयोग करके दीवारों को आकर्षित करता हूं जो मैंने
यहां के बारे में लिखा था। Gluing दीवारों के साथ समस्याओं के मामले में, सब कुछ तुरंत दिखाई देता है। बनावट के बजाय, आप दो-आयामी सरणी का उपयोग कर सकते हैं या तुरंत तीन-आयामी मॉडल के साथ काम कर सकते हैं।
बाहरी दीवारों को बहुत सरलता से उत्पन्न किया जा सकता है। हम मनमाने आकार के कई काले आयत बनाते हैं, और उनके ऊपर हम एक ही सफेद वाले और प्रत्येक तरफ एक पिक्सेल कम खींचते हैं। यह कई अलग-अलग घरों में बदल जाता है। उन्हें तीन आयामी भी बनाया जा सकता है और छत के साथ कवर किया जा सकता है।
वॉइस ऑफ केनव्स्की: हालांकि, यह एक पूरी तरह से अलग कहानी है।

नीचे दिए गए लिंक पर आप समाप्त परियोजना के बायनेरिज़ और स्रोत कोड देख सकते हैं।
एकता वेब प्लेयर |
विंडोज |
लिनक्स |
मैक |
गिटहब स्रोतशिफ्ट - यादृच्छिक कमरों के साथ यादृच्छिक बाहरी दीवारें बनाता है
Ctrl - यादृच्छिक कमरों के साथ परीक्षण बनावट लोड करें
दर्ज करें - सभी कमरे निकालें और एक परीक्षण बनावट लोड करें
स्पेसबार - कमरों की वृद्धि को रोकें
अल्फ़ाबेटिक कीबोर्ड पर यूनिट - मुफ्त कोशिकाओं के लिए खोज का विज़ुअलाइज़ेशन सक्षम करें
एक मुक्त क्षेत्र पर बाईं माउस बटन - कमरा जोड़ें
Esc - बाहर निकलें
लिनक्स उपयोगकर्ताओं के लिए: "Chmod + x ProceduralExperiments.x86" के साथ निष्पादन योग्य प्रक्रिया। X 86 फ़ाइल बनाएं और इसे चलाएं।