किसी निर्धारित त्रिभुज के साथ ग्रिड अंतर में कौन सी कोशिकाएं निर्धारित करें?


10

मैं वर्तमान में एक 2D AI सिमुलेशन लिख रहा हूं, लेकिन मैं पूरी तरह से निश्चित नहीं हूं कि यह कैसे जांचें कि एक एजेंट की स्थिति दूसरे के देखने के क्षेत्र के भीतर है या नहीं।

वर्तमान में, मेरा विश्व विभाजन सरल सेल-स्पेस विभाजन (एक ग्रिड) है। मैं देखने के क्षेत्र का प्रतिनिधित्व करने के लिए एक त्रिकोण का उपयोग करना चाहता हूं, लेकिन मैं उन कोशिकाओं की गणना कैसे कर सकता हूं जो त्रिकोण के साथ प्रतिच्छेद करते हैं?

इस तस्वीर के समान: यहाँ छवि विवरण दर्ज करें

लाल क्षेत्र वे कोशिकाएं हैं जिनकी मैं गणना करना चाहता हूं, यह जांच कर कि क्या त्रिकोण उन कोशिकाओं को काटता है या नहीं।

अग्रिम में धन्यवाद।

संपादित करें:

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


क्या आप कोशिकाओं को त्रिभुजों में विभाजित नहीं कर सकते हैं, और त्रिकोण-त्रिकोण का परीक्षण कर सकते हैं?
कम्युनिस्ट डक

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

यहाँ किसी भी उत्तर को पसंद न करें; हालाँकि, इस सवाल के कुछ बहुत अच्छे जवाब हैं: gamedev.stackexchange.com/q/81267/63053
एंड्रयू

जवाबों:


6

अपने फ़ॉव त्रिकोण के तीन कोनों की गणना करें, उन्हें सही तरीके से सामना करने के लिए घुमाएँ और ऐसे करें, और फिर उनमें से एक करें:

1) सभी संभावित लक्ष्यों के लिए एक बिंदु-इन-त्रिकोण परीक्षण करें

2) इस त्रिकोण के बाउंडिंग बॉक्स की गणना करें, और इस बाउंडिंग बॉक्स में कोशिकाओं के सभी संभावित लक्ष्यों के लिए एक बिंदु-इन-ट्रायंगल परीक्षण करें - यह डिबग करने के लिए बहुत सीधा कोड होगा

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

3) इस त्रिभुज को ise rasterise ’करें और कोशिकाओं की जाँच करें कि यह 'पेंट’ करता है - संभवतः सबसे कुशल कोड, लेकिन शायद केवल थोड़े से के रूप में मैं कैश मिस समय पर इसके सभी प्रभुत्व का अनुमान लगाऊंगा और इस बात पर निर्भर करता है कि आपकी कोशिकाएँ कितनी जटिल हैं और कैसे व्याप्त हैं। वो हैं।

एक वैकल्पिक दृष्टिकोण FOV को ऑफ-स्क्रीन बिटमैप पर रेंडर करना है और फिर अपनी प्रत्येक ऑब्जेक्ट के लिए पिक्सेल मान पढ़ना है; आप 'अनमिक्स पेंट' नहीं कर सकते हैं, लेकिन सीमित संख्या में वस्तुओं के साथ और ध्यान से अपना पेंट चुनकर आप यह देख सकते हैं कि किसने क्या देखा। यह दृष्टिकोण उस गेम के समान है जो उपयोगकर्ता द्वारा क्लिक किए गए कितने गेम काम करता है - वे हिट-क्षेत्रों के लिए ठोस रंगों का उपयोग करके दृश्य ऑफ-स्क्रीन खींचते हैं। जीपीयू त्रिभुज भराव में बहुत तेज है ...


+1 इसके लिए धन्यवाद, मैंने त्रिकोण के लिए एक बाउंडिंग बॉक्स का उपयोग किया है ताकि जल्दी से उपयुक्त कोशिकाओं का चयन किया जा सके और यह निर्धारित करने के लिए एक बिंदु-इन-ट्रायंगल परीक्षण का उपयोग किया है कि उन सेल के कौन से सदस्य फील्ड-ऑफ-व्यू के भीतर हैं :)
रे डे

3

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

मैं बहुत से चमक रहा हूँ विवरणों लेकिन यह मूल विचार है। यदि आप "सॉफ़्टवेयर रेंडर" और "त्रिकोण रेखांकन" के लिए शिकार करते हैं, तो आपको संभवतः कुछ और विवरण मिलेंगे। यह एक अच्छी तरह से हल की गई समस्या है। आपका ग्राफिक्स कार्ड एक फ्रेम के लाखों बार ऐसा कर रहा है।

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


1
यह बहुत अच्छा तरीका है।
नोटाबिन

2

मैं सटीक एक ही समस्या को हल करने के लिए स्कैनलाइन एल्गोरिथ्म की भिन्नता का उपयोग कर रहा हूं। मैंने तीन त्रिभुज बिंदुओं को उनकी ऊँचाई से छाँटकर शुरू किया। मैं तब मूल रूप से जांचता हूं कि दो किनारे बाईं तरफ हैं या दाएं तरफ। दो किनारों के साथ पक्ष के लिए, आपको उन्हें पंक्ति में चिह्नित करना होगा जहां आप बदलते हैं कि कौन सा किनारा आपकी पंक्तियों को परिसीमित करता है। एक किनारे के साथ पक्ष के लिए, आप हमेशा इसका उपयोग कर सकते हैं।

तो फिर प्रत्येक पंक्ति के लिए, मुझे पता है कि किन दो किनारों ने इसे सीमांकित किया है, और मैं एक्स-दिशा में ऊपरी और निचले सीमा की गणना कर सकता हूं। यह काफी जटिल लगता है, लेकिन यह कोड की सिर्फ कुछ पंक्तियों तक सीमित होता है। सुनिश्चित करें कि आप उस विशेष मामले को संभालते हैं जहां एक किनारे पूरी तरह से क्षैतिज है!


2

प्रत्येक पंक्ति के लिए कॉलम की एक सीमा बनाए रखने के बारे में कैसे त्रिकोण में हैं? आप क्या कर सकते हैं प्रत्येक पंक्ति के लिए न्यूनतम और अधिकतम कॉलम सेट करें जहां प्रत्येक बिंदु है, और जहां प्रत्येक त्रिकोण रेखा एक क्षैतिज पंक्ति विभाजक रेखा को पार करती है।

public class Point
{
    public float X;
    public float Y;
    public Point(float x, float y) { this.X = x; this.Y = y; }
}

public class Line
{
    float ROW_SIZE = 100f;
    float COL_SIZE = 100f;

    public Point P1, P2; // P1 has the lowest Y
    public float Slope, Intercept; // set in constructor
    public bool IsVertical;

    public Line(Point p1, Point p2)
    {
        if (p1.Y > p2.Y) { P1 = p2; P2 = p1; } // p1 has lowest Y
        else { P1 = p1; P2 = p2; }
        IsVertical = (p1.X == p2.X);
        if (!IsVertical) { Slope = (p2.Y - p1.Y) / (p2.X - p1.X); Intercept = p1.Y - Slope * p1.X; }
    }

    public void ExpandRanges(int[] minCol, int[] maxCol)
    {
        // start out at row, col where P1 is, which has lowest Y
        int row = (int)(P1.Y / ROW_SIZE);
        int col = (int)(P1.X / COL_SIZE);
        int lastRow = (int)(P2.Y / ROW_SIZE);
        int lastCol = (int)(P2.X / COL_SIZE);

        // expand row to include P1
        minCol[row] = Math.Min(col, minCol[row]); maxCol[row] = Math.Max(col, maxCol[row]);

        // now we find where our line intercepts each horizontal line up to P2
        float currY = P1.Y;
        float currX = P1.X;
        while (row < lastRow)
        {
            row = row + 1;
            float rowY = row * ROW_SIZE;
            float diffY = rowY - currY;
            float diffX = IsVertical ? 0f : diffY / Slope;
            currY = currY + diffY;
            currX = currX + diffX;
            col = (int)(currX / COL_SIZE);

            // expand rows above and below dividing line to include point
            minCol[row - 1] = Math.Min(col, minCol[row - 1]);
            maxCol[row - 1] = Math.Max(col, maxCol[row - 1]);
            minCol[row] = Math.Min(col, minCol[row]);
            maxCol[row] = Math.Max(col, maxCol[row]);
        }

        // expand last row to include P2
        minCol[lastRow] = Math.Min(lastCol, minCol[lastRow]);
        maxCol[lastRow] = Math.Max(lastCol, maxCol[lastRow]);
    }

    public static void Test()
    {
        Point p1 = new Point(160, 250);
        Point p2 = new Point(340, 250);
        Point p3 = new Point(250, 40);
        Line l1 = new Line(p1, p2);
        Line l2 = new Line(p2, p3);
        Line l3 = new Line(p3, p1);

        Line[] lines = { l1, l2, l3 };

        int rowCount = 4;
        int[] minCol = new int[rowCount];
        int[] maxCol = new int[rowCount];
        for (int i = 0; i < rowCount; i++)
        {
            minCol[i] = int.MaxValue;
            maxCol[i] = int.MinValue;
        }

        for (int i = 0; i < lines.Length; i++)
            lines[i].ExpandRanges(minCol, maxCol);

        for (int i = 0; i < rowCount; i++)
            Console.WriteLine("Row {0}:  {1} - {2}", i, minCol[i], maxCol[i]);
    }
}

आउटपुट:

Row 0:  2 - 2
Row 1:  1 - 3
Row 2:  1 - 3
Row 3:  2147483647 - -2147483648

1

रॉगुलाइक समुदाय में कुछ एल्गोरिथ्म कार्य किए गए हैं जो टाइल आधारित दुनिया में FOV / LOS / प्रकाश व्यवस्था से संबंधित हैं।

शायद आप इस पृष्ठ पर कुछ पा सकते हैं जो आपकी समस्या को हल करने में मदद के लिए इस्तेमाल किया जा सकता है: http://roguebasin.roguelikedevelopment.org/index.php?title=Field_of_Vision

विशेष रूप से "अनुमेय FOV" आपकी स्थिति के लिए सबसे अधिक लागू हो सकता है।

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