मैं सही क्रम में आइसोमेट्रिक स्प्राइट को कैसे सॉर्ट करता हूं?


19

एक सामान्य टॉप-डाउन 2D गेम में, स्क्रीन y अक्ष का उपयोग छवियों को सॉर्ट करने के लिए किया जा सकता है। इस उदाहरण में पेड़ों को ठीक से सॉर्ट किया गया है लेकिन आइसोमेट्रिक दीवारें नहीं हैं:

उदाहरण छवि: स्क्रीन y द्वारा क्रमबद्ध

वॉल 2 दीवार 1 के नीचे एक पिक्सेल है इसलिए इसे दीवार 1 के बाद खींचा जाता है, और शीर्ष पर समाप्त होता है।

यदि मैं आइसोमेट्रिक y अक्ष द्वारा छाँटता हूँ तो दीवारें सही क्रम में दिखाई देती हैं लेकिन पेड़ नहीं हैं:

उदाहरण छवि: आइसोमेट्रिक y द्वारा क्रमबद्ध

मैं इसे सही तरीके से कैसे करूं?


3
लगता है कि आपने पेंटर के एल्गोरिथ्म में आम समस्याओं को मारा है। "सामान्य" समाधान z- बफर =) का उपयोग करना है। कुछ वर्कअराउंड में ऑब्जेक्ट सेंटर को कुछ कोने के बजाय सॉर्ट कुंजी के रूप में उपयोग करना शामिल है।
जरी कोमप्पा

जवाबों:


12

आइसोमेट्रिक गेम कार्यात्मक रूप से 3 डी हैं, इसलिए आंतरिक रूप से, आपको गेम में प्रत्येक इकाई के लिए 3 डी निर्देशांक संग्रहीत करना चाहिए। आपके द्वारा चुने गए वास्तविक निर्देशांक मनमाने हैं, लेकिन मान लीजिए कि X और Y दो ऑन-द-ग्राउंड कुल्हाड़ियां हैं, और Z हवा में जमीन से ऊपर है।

रेंडर करने वाले को स्क्रीन पर सामान खींचने के लिए उस 2D में प्रोजेक्ट करना होगा। "आइसोमेट्रिक" एक ऐसा प्रक्षेपण है। 3 डी से 2 डी isometrically के लिए पेश करना बहुत आसान है। मान लें कि एक्स अक्ष ऊपर-बाएं से नीचे-दाएं और प्रत्येक दो क्षैतिज पिक्सेल के लिए एक पिक्सेल नीचे जाता है। इसी तरह, वाई अक्ष ऊपर-दाएं से नीचे-बाएं जाता है। Z अक्ष सीधे ऊपर जाता है। 3 डी से 2 डी में परिवर्तित करने के लिए बस है:

function projectIso(x, y, z) {
    return {
        x: x - y,
        y: (x / 2) + (y / 2) - z
    };
}

अब आपके मूल प्रश्न पर, छँटाई। अब जब हम अपनी वस्तुओं के साथ सीधे 3 डी में काम कर रहे हैं, तो छंटाई बहुत सरल हो जाती है। हमारे यहाँ समन्वय स्थान में, सबसे दूर के स्प्राइट में सबसे कम x, y और z निर्देशांक होते हैं (अर्थात स्क्रीन से तीनों अक्ष बाहर इंगित करते हैं)। तो आप उन लोगों के योग द्वारा उन्हें क्रमबद्ध करें:

function nearness(obj) {
    return obj.x + obj.y + obj.z;
}

function closer(a, b) {
    if (nearness(a) > nearness(b)) {
        return "a";
    } else {
        return "b";
    }
}

हर फ्रेम पर अपनी संस्थाओं को फिर से छांटने से बचने के लिए, यहां विस्तृत एक कबूतर की छँटाई का उपयोग करें


1
मुझे पता है कि यह पुराना है, एक अच्छी शुरुआत है लेकिन क्या आप जानते हैं कि किसी वस्तु के 3 डी सीमा को केवल इसके अनुवाद में शामिल नहीं किया जा सकता है। जब वे गहराई को ओवरलैप कर रहे होते हैं तो छंटाई अधिक जटिल हो जाती है।
रोब

4

यह मानते हुए कि आपके स्प्राइट्स टाइलों के आयताकार सेट हैं जो आयताकार हैं (यदि वे मनमाना सेटों पर कब्जा करते हैं, तो आप सामान्य मामले में बिल्कुल भी सही ढंग से आकर्षित नहीं कर सकते हैं), समस्या यह है कि तत्वों के बीच कुल क्रम संबंध नहीं है, इसलिए आप सॉर्ट कर सकते हैं एक तरह का उपयोग करके उन्हें ओ (नॉग्लन) की तुलना में परिणाम होगा।

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

एक उपाय यह है कि तुलना (दानी द्वारा उल्लिखित) का उपयोग किया जाए और प्रत्येक वस्तु की एक-दूसरे से तुलना करके उनकी निर्भरता का निर्धारण किया जाए और एक निर्भरता ग्राफ बनाया जाए (जो कि DAG होगा)। फिर ड्राइंग ऑर्डर निर्धारित करने के लिए ग्राफ पर एक टोपोलॉजिकल सॉर्ट करें। यदि बहुत अधिक वस्तुएँ नहीं हैं, तो यह काफी तेज़ हो सकता है (यह O(n^2))।

एक और उपाय है कि (शेष - छद्म के लिए ) क्वाड ट्री का उपयोग किया जाए और इसमें सभी वस्तुओं के आयतों को संग्रहीत किया जाए।

फिर सभी ऑब्जेक्ट्स X के माध्यम से पुनरावृत्ति करें, और यह जांचने के लिए कि क्या कोई ऑब्जेक्ट में ऑब्जेक्ट X के ऊपर पट्टी में कोई ऑब्जेक्ट Y हैं, जो सबसे बाईं ओर से शुरू होता है और ऑब्जेक्ट X के सबसे दाएं कोने से समाप्त होता है - ऐसे सभी Y, Y के लिए। - X. इस तरह, आपको अभी भी एक ग्राफ़ बनाना होगा और स्थाई रूप से सॉर्ट करना होगा।

लेकिन आप इससे बच सकते हैं। आप वस्तुओं की एक सूची Q का उपयोग करते हैं, और वस्तुओं की एक तालिका T. आप x- अक्ष (एक पंक्ति) पर छोटे से लेकर बड़े मानों तक सभी दृश्यमान स्लॉट्स को पुन: क्रमबद्ध करते हैं, जो कि y- अक्ष पर पंक्ति से पंक्ति में चलते हैं। यदि उस स्लॉट में किसी ऑब्जेक्ट का निचला कोना है, तो निर्भरता निर्धारित करने के लिए ऊपर की प्रक्रिया करें। यदि कोई वस्तु X किसी अन्य वस्तु Y पर निर्भर करती है जो आंशिक रूप से उसके ऊपर है (Y <- X), और ऐसा प्रत्येक Y पहले से ही Q में है, तो X को Q में जोड़ें। यदि कुछ Y है जो Q में नहीं है, तो X को जोड़ें T और निरूपित करें कि Y <- X. हर बार जब आप Q में कोई ऑब्जेक्ट जोड़ते हैं, तो आप T में लंबित वस्तुओं की निर्भरता को हटा देते हैं। यदि सभी निर्भरताएं हटा दी जाती हैं, तो T से किसी ऑब्जेक्ट को Q में स्थानांतरित कर दिया जाता है।

हम मान रहे हैं कि वस्तु स्प्राइट्स नीचे, बाएं या दाएं (केवल आपकी तस्वीर के पेड़ों की तरह) शीर्ष पर अपने स्लॉट्स से बाहर नहीं झांक रही है। इससे बड़ी संख्या में ऑब्जेक्ट के लिए प्रदर्शन में सुधार होना चाहिए। यह दृष्टिकोण फिर से होगा O(n^2), लेकिन केवल सबसे खराब स्थिति में जिसमें अजीब आकार की वस्तुएं और / या वस्तुओं के अजीब विन्यास शामिल हैं। ज्यादातर मामलों में, यह है O(n * logn * sqrt(n))। अपने स्प्राइट्स की ऊँचाई को जानकर sqrt(n)आप इसे समाप्त कर सकते हैं , क्योंकि आपको ऊपर की पूरी पट्टी की जाँच करने की आवश्यकता नहीं है। स्क्रीन पर ऑब्जेक्ट्स की संख्या के आधार पर, आप एक ट्री के साथ क्वाड ट्री को बदलने की कोशिश कर सकते हैं, जिसमें यह संकेत मिलता है कि कौन से स्लॉट लिए गए हैं (अगर कई ऑब्जेक्ट हैं तो समझ में आता है)।

अंत में, कुछ विचारों के लिए इस स्रोत कोड का निरीक्षण करने के लिए स्वतंत्र महसूस करें: https://github.com/axel22/sages/blob/master/src/gui/scala/name/brijest/sages/gui/Canvas.scala


2

मुझे नहीं लगता कि एक गणितीय समाधान है। आपके पास संभवत: 2 डी दुनिया में पर्याप्त डेटा नहीं है जो आपके आइटम में रह रहे हैं। यदि आपकी दीवारों को एक्स पर प्रतिबिंबित किया गया था तो वे "सही" क्रम में होंगे। तब फिर से आप किसी भी तरह छवि के बाउंडिंग बॉक्स के साथ ओवरलैप परीक्षण करने में सक्षम हो सकते हैं, लेकिन यह एक ऐसा क्षेत्र है जिससे मैं परिचित नहीं हूं।

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

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


2

सही है आइसोमेट्रिक छांटना कठिन है। लेकिन पहले दृष्टिकोण के लिए, अपने आइटम को ठीक से सॉर्ट करने के लिए, आपको प्रत्येक ओवरलैपिंग ऑब्जेक्ट के साथ अधिक जटिल तुलना फ़ंक्शन का उपयोग करना चाहिए। इस फ़ंक्शन को इस स्थिति की जांच करनी चाहिए: एक ओवरलैपिंग ऑब्जेक्ट "ए" यदि "बी" के पीछे है:

(a.posX + a.sizeX <= b.posX) या (a.posY + a.sizeY <= b.posY) या (a.posZ + a.sizeZ <= b.posZ)

बेशक, यह एक भोली isometric कार्यान्वयन के लिए एक पहला विचार है। अधिक जटिल परिदृश्य के लिए (यदि आप रोटेशन देखना चाहते हैं, तो z- अक्ष पर प्रति पिक्सेल स्थिति, आदि) आपको और अधिक स्थितियों की जांच करने की आवश्यकता होगी।


+1, यदि आपके पास अलग-अलग चौड़ाई / ऊँचाई वाली टाइलें हैं, तो इस उत्तर में तुलना फ़ंक्शन को देखें।
मुलाहो

2

मैं एक बहुत ही सरल सूत्र का उपयोग करता हूं जो OpenGL में मेरे छोटे सममितीय इंजन के साथ अच्छा काम करता है:

आप में से प्रत्येक ऑब्जेक्ट (पेड़, फर्श टाइल, वर्ण, ...) स्क्रीन पर एक एक्स और वाई स्थिति है। आपको DEPTH TESTING को सक्षम करने और प्रत्येक मान के लिए अच्छा Z मान खोजने की आवश्यकता है। आप बस निम्नलिखित के लिए कर सकते हैं:

z = x + y + objectIndex

मैं फर्श और वस्तुओं के लिए अलग-अलग सूचकांक का उपयोग करता हूं जो फर्श के ऊपर होगा (मंजिल के लिए 0 और सभी वस्तुओं के लिए 1 ऊंचाई है)। यह ठीक काम करना चाहिए।



1

यदि आप समान x स्थिति में y मानों की तुलना करते हैं, तो यह हर बार काम करेगा। इसलिए, केंद्र से केंद्र की तुलना न करें। इसके बजाय एक स्प्राइट के केंद्र की तुलना दूसरे स्प्राइट पर एक ही एक्स स्थिति के साथ करें।

यहाँ छवि विवरण दर्ज करें

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

एक आसान तरीका यह है कि सभी स्प्राइट्स को तीन समूहों में विभाजित करें: एक्स एक्सिस के साथ विकर्ण, वाई अक्ष और फ्लैट के साथ विकर्ण। यदि दो ऑब्जेक्ट एक ही अक्ष के साथ दोनों विकर्ण हैं, तो उन्हें अन्य अक्ष के आधार पर सॉर्ट करें।


0

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


0

यह वास्तव में एक उत्तर नहीं है, लेकिन सिर्फ एक टिप्पणी और एक अप-वोट मैं इस axel22 के उत्तर को यहां देना चाहूंगा /gamedev//a/8181/112940

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

अपने इंजन में मैं चीजों को "पुराने स्कूल", शुद्ध 2 डी करना चाहता था। और मैंने अपना बहुत समय बिताया है ताकि मेरे दिमाग में यह जानने की कोशिश की जाए कि मेरी कॉल "सॉर्ट" करने के लिए क्यों है (मेरे मामले में यह c ++ std :: सॉर्ट था) कुछ मैप कॉन्फ़िगरेशन पर सही तरीके से काम नहीं कर रहा था।

केवल जब मैंने महसूस किया कि यह एक "आंशिक-क्रम" स्थिति है, तो मैं इसे हल करने में सक्षम था।

अब तक मैंने वेब पर जितने भी वर्किंग सॉल्यूशन ढूंढे हैं, उनमें किसी तरह की टोपोलॉजिकल सॉर्टिंग का इस्तेमाल किया ताकि समस्या से सही तरीके से निपटा जा सके। टोपोलॉजिकल सॉर्टिंग जाने का रास्ता लगता है।

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