क्या XNA में पिक्सेल-परफेक्ट टक्कर का पता लगाने का एक अच्छा तरीका है?


12

क्या XNA में पिक्सेल-सटीक टक्कर का पता लगाने के लिए एक जाना-माना तरीका (या शायद पुन: प्रयोज्य बिट है) है?

मुझे लगता है कि यह पहले-पास, टक्करों के लिए त्वरित-परीक्षण के लिए बहुभुज (बक्से / त्रिकोण / मंडलियों) का भी उपयोग करेगा, और यदि यह परीक्षण टकराव का संकेत देता है, तो यह प्रति-पिक्सेल टक्कर की खोज करेगा।

यह जटिल हो सकता है, क्योंकि हमें पैमाने, रोटेशन और पारदर्शिता के लिए जिम्मेदार होना चाहिए।

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


2
बहुभुज या स्प्राइट?
डोपेलग्रेनर

मुझे यकीन नहीं है। Xna दोनों का समर्थन करता है? मेरे संपादन में दोनों के संयोजन का उल्लेख है, क्योंकि बाउंडिंग-बॉक्स परीक्षण एक तेज़ प्रथम-पास हैं।
as999999

1
टकराव का पता लगाना इस बात पर निर्भर करेगा कि आप 3D / 2D मॉडल का उपयोग कर रहे हैं या स्प्राइट के आधार पर। एक में पिक्सेल होते हैं। दूसरे में कोने और किनारे हैं।
doppelgreener

ठीक है, मैं देख रहा हूँ कि आप अभी क्या कर रहे हैं। मैं स्प्राइट का उपयोग कर रहा हूं। हालांकि मेरा मानना ​​है कि एक्सएनए उन्हें एक बनावट वाले बहुभुज के रूप में लागू करता है।
ashes999

जवाबों:


22

मैं देखता हूं कि आपने प्रश्न को 2d के रूप में टैग किया है, इसलिए मैं आगे जाऊंगा और अपना कोड दूंगा:

class Sprite {

    [...]

    public bool CollidesWith(Sprite other)
    {
        // Default behavior uses per-pixel collision detection
        return CollidesWith(other, true);
    }

    public bool CollidesWith(Sprite other, bool calcPerPixel)
    {
        // Get dimensions of texture
        int widthOther = other.Texture.Width;
        int heightOther = other.Texture.Height;
        int widthMe = Texture.Width;
        int heightMe = Texture.Height;

        if ( calcPerPixel &&                                // if we need per pixel
            (( Math.Min(widthOther, heightOther) > 100) ||  // at least avoid doing it
            ( Math.Min(widthMe, heightMe) > 100)))          // for small sizes (nobody will notice :P)
        {
            return Bounds.Intersects(other.Bounds) // If simple intersection fails, don't even bother with per-pixel
                && PerPixelCollision(this, other);
        }

        return Bounds.Intersects(other.Bounds);
    }

    static bool PerPixelCollision(Sprite a, Sprite b)
    {
        // Get Color data of each Texture
        Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
        a.Texture.GetData(bitsA);
        Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
        b.Texture.GetData(bitsB);

        // Calculate the intersecting rectangle
        int x1 = Math.Max(a.Bounds.X, b.Bounds.X);
        int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width);

        int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y);
        int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height);

         // For each single pixel in the intersecting rectangle
         for (int y = y1; y < y2; ++y)
         {
             for (int x = x1; x < x2; ++x)
             {
                 // Get the color from each texture
                 Color a = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y)*a.Texture.Width];
                 Color b = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y)*b.Texture.Width];

                 if (a.A != 0 && b.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
                 {
                     return true;
                 }
             }
         }
        // If no collision occurred by now, we're clear.
        return false;
    }

    private Rectangle bounds = Rectangle.Empty;
    public virtual Rectangle Bounds
    {
        get
        {
            return new Rectangle(
                (int)Position.X - Texture.Width,
                (int)Position.Y - Texture.Height,
                Texture.Width,
                Texture.Height);
        }

    }

संपादित करें : जबकि यह कोड लगभग आत्म व्याख्यात्मक है, मुझे टिप्पणी नहीं करने के लिए बुरा लगा, इसलिए मैंने कुछ जोड़ा;) मुझे बिटवाइज़ ऑपरेशंस से भी छुटकारा मिल गया क्योंकि यह मूल रूप से क्या कर रहा था। रंग संपत्ति अधिक जटिल तरीके से करती है ;)


कोई टिप्पणी या स्पष्टीकरण के साथ एक कोड डंप के लिए डाउन-वोट।
हल्दीहोबो

12
कोई भी स्पष्टीकरण बस कोड को पुनर्स्थापित करेगा, और कोड काफी सीधा है।

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

1
हाँ, मैं उसके बारे में भूल गया! कोड विचार में परिवर्तन नहीं करता है। अभी मेरे पास संपादित करने का समय नहीं है, लेकिन आप मेरे द्वारा किए जाने तक Collision Transformed नमूने पर एक नज़र डाल सकते हैं: create.msdn.com/en-US/education/catalog/tutorial/…
pek

1
बस पांडित्यपूर्ण, लेकिन आपको केवल आवश्यकता है: CollidesWith(Sprite other, bool calcPerPixel = true);:)
जोनाथन कॉनेल

4

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

http://xbox.create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel_transformed

मैंने अपने 2 डी निशानेबाजों के खेल में भी रीमेर ग्रोटोजन्स को दिलचस्प पाया। http://www.riemers.net/eng/Tutorials/XNA/Csharp/series2d.php

(इसे प्राप्त करने में उसे थोड़ा समय लगता है ... http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Coll_Detection_Overview.php ... लेकिन आप इसे देखने के लिए साथ चलना चाह सकते हैं। समस्या वह हल कर रहा है)

लेकिन मैं आपको सावधान करता हूं कि रीमर्स नमूना XNA 4.0 नहीं है और इसे चलाने के लिए आपको थोड़ा काम करना पड़ सकता है। हालांकि यह मुश्किल या रहस्यमय काम नहीं है।


महान लिंक, लेकिन पुराने लिंक; मैंने अपने समाधान के लिए इनका उपयोग पहले ही कर लिया है।
ashes999

1
बहुत बढ़िया। मैं सिर्फ यह आंकता हूं कि जब कोई खोजता है तो वे आपके प्रश्न का पता लगा सकते हैं और उनके पास अधिक संसाधन होंगे।
क्रिस गोमेज़

0

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

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

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