2 ডি টাইল মানচিত্রে "ভিশন শঙ্কু" গণনা করার কার্যকর উপায়?


13

আমি টাইল মানচিত্রে (নির্দিষ্ট পরিসীমা এবং মুখের কোণে) কোনও নির্দিষ্ট দিকের মুখোমুখি হলে কোন নির্দিষ্ট ইউনিট "দেখতে" পারে তা কোন টাইলগুলি গণনা করার চেষ্টা করছি। সবচেয়ে সহজ উপায় হ'ল প্রতিটি টাইলের বাইরের দিকে বাইরের একটি নির্দিষ্ট সংখ্যক টাইলস এবং রাইকাস্ট। তবে আমি কিছুটা দক্ষতার জন্য আশা করছি। একটি ছবি হাজার শব্দ বলছে:

দৃষ্টি শঙ্কু

লাল বিন্দুটি ইউনিট (যিনি উপরের দিকে মুখ করে আছেন)। আমার লক্ষ্য হলুদ টাইলস গণনা করা। সবুজ ব্লকগুলি দেয়াল (দেয়াল টাইলগুলির মধ্যে রয়েছে এবং আপনি দুটি টাইলের মধ্যে যেতে পারবেন কিনা তা পরীক্ষা করা সহজ)। নীল রেখাটি "রেইস্টকিং" পদ্ধতির মতো এমন কিছু উপস্থাপন করে যা আমি বলছিলাম, তবে আমার এটি করার দরকার নেই।

সম্পাদনা: ইউনিটগুলি কেবল উত্তর / দক্ষিণ / পূর্ব / পশ্চিমের দিকে মুখোমুখি হতে পারে (0, 90, 180, বা 270 ডিগ্রি) এবং এফওভি সর্বদা 90 ডিগ্রি থাকে। কিছু গণনা সহজ করা উচিত। আমি ভাবছি কিছু ধরণের পুনরাবৃত্ত-ইশ / স্ট্যাক-ভিত্তিক / সারি-ভিত্তিক অ্যালগরিদম আছে তবে আমি এটি বেশিরভাগই খুঁজে বের করতে পারি না।

ধন্যবাদ!


মুখের দিকটি কোনও কোণ বা কেবল 0,45,90, .. ইত্যাদি হতে পারে?
ওয়েস্ট

এছাড়াও এফওভি সর্বদা 90 হয়?
J_F_B_M

@ ওয়ানড্রা কেবল এনএসইডাব্লু (0, 90, 180, 270)।
রবার্ট ফ্রেজার

@ ল্যারিথিয়ান - হ্যাঁ, এফওভি সর্বদা 90 হয় This আমি ভাবছি গভীরতা-প্রথম অনুসন্ধানের ভিত্তিতে কোনও উপায় থাকতে পারে, তবে আমি এটির বেশিরভাগটি বের করতে পারি না।
রবার্ট ফ্রেজার

এটি রোগুলাইকগুলিতে ব্যবহৃত দৃষ্টিভঙ্গির অ্যালগরিদমের মতো শোনাচ্ছে । তারা কিছু অনুপ্রেরণা হতে পারে। আমি সমস্যার জন্য বিভিন্ন পদ্ধতির তালিকাবদ্ধ একটি পৃষ্ঠা পেয়েছি ।
আনকো

উত্তর:


13

হ্যাঁ আমি একটি গবেষণা কাগজ খুঁজে পেয়েছি!

গণনা ব্যয়ের শ্যাডো ম্যাপিংয়ের বিষয়টি বেশ পরিষ্কার বিজয়ী বলে মনে হচ্ছে।

এখানে চিত্র বর্ণনা লিখুন

ব্যবহৃত অ্যালগরিদম এখানে পাওয়া যাবে এবং নীচে প্রাসঙ্গিক একটি সি # বাস্তবায়ন এখানে পাওয়া যাবে

    #region FOV algorithm

    //  Octant data
    //
    //    \ 1 | 2 /
    //   8 \  |  / 3
    //   -----+-----
    //   7 /  |  \ 4
    //    / 6 | 5 \
    //
    //  1 = NNW, 2 =NNE, 3=ENE, 4=ESE, 5=SSE, 6=SSW, 7=WSW, 8 = WNW

    /// <summary>
    /// Start here: go through all the octants which surround the player to
    /// determine which open cells are visible
    /// </summary>
    public void GetVisibleCells()
    {
        VisiblePoints = new List<Point>();
        foreach (int o in VisibleOctants)
            ScanOctant(1, o, 1.0, 0.0);

    }

    /// <summary>
    /// Examine the provided octant and calculate the visible cells within it.
    /// </summary>
    /// <param name="pDepth">Depth of the scan</param>
    /// <param name="pOctant">Octant being examined</param>
    /// <param name="pStartSlope">Start slope of the octant</param>
    /// <param name="pEndSlope">End slope of the octance</param>
    protected void ScanOctant(int pDepth, int pOctant, double pStartSlope, double pEndSlope)
    {

        int visrange2 = VisualRange * VisualRange;
        int x = 0;
        int y = 0;

        switch (pOctant)
        {

            case 1: //nnw
                y = player.Y - pDepth;
                if (y < 0) return;

                x = player.X - Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (x < 0) x = 0;

                while (GetSlope(x, y, player.X, player.Y, false) >= pEndSlope)
                {
                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {
                        if (map[x, y] == 1) //current cell blocked
                        {
                            if (x - 1 >= 0 && map[x - 1, y] == 0) //prior cell within range AND open...
                                //...incremenet the depth, adjust the endslope and recurse
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x - 0.5, y + 0.5, player.X, player.Y, false));
                        }
                        else
                        {

                            if (x - 1 >= 0 && map[x - 1, y] == 1) //prior cell within range AND open...
                                //..adjust the startslope
                                pStartSlope = GetSlope(x - 0.5, y - 0.5, player.X, player.Y, false);

                                VisiblePoints.Add(new Point(x, y));
                        }                            
                    }
                    x++;
                }
                x--;
                break;

            case 2: //nne

                y = player.Y - pDepth;
                if (y < 0) return;                  

                x = player.X + Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (x >= map.GetLength(0)) x = map.GetLength(0) - 1;

                while (GetSlope(x, y, player.X, player.Y, false) <= pEndSlope)
                {
                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {
                        if (map[x, y] == 1)
                        {
                            if (x + 1 < map.GetLength(0) && map[x + 1, y] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x + 0.5, y + 0.5, player.X, player.Y, false));
                        }
                        else
                        {
                            if (x + 1 < map.GetLength(0) && map[x + 1, y] == 1)
                                pStartSlope = -GetSlope(x + 0.5, y - 0.5, player.X, player.Y, false);

                            VisiblePoints.Add(new Point(x, y));
                        }                            
                    }
                    x--;
                }
                x++;
                break;

            case 3:

                x = player.X + pDepth;
                if (x >= map.GetLength(0)) return;

                y = player.Y - Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth))); 
                if (y < 0) y = 0;

                while (GetSlope(x, y, player.X, player.Y, true) <= pEndSlope)
                {

                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (y - 1 >= 0 && map[x, y - 1] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x - 0.5, y - 0.5, player.X, player.Y, true));
                        }
                        else
                        {
                            if (y - 1 >= 0 && map[x, y - 1] == 1)
                                pStartSlope = -GetSlope(x + 0.5, y - 0.5, player.X, player.Y, true);

                            VisiblePoints.Add(new Point(x, y));
                        }                           
                    }
                    y++;
                }
                y--;
                break;

            case 4:

                x = player.X + pDepth;
                if (x >= map.GetLength(0)) return;

                y = player.Y + Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (y >= map.GetLength(1)) y = map.GetLength(1) - 1;

                while (GetSlope(x, y, player.X, player.Y, true) >= pEndSlope)
                {

                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (y + 1 < map.GetLength(1)&& map[x, y + 1] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x - 0.5, y + 0.5, player.X, player.Y, true));
                        }
                        else
                        {
                            if (y + 1 < map.GetLength(1) && map[x, y + 1] == 1)
                                pStartSlope = GetSlope(x + 0.5, y + 0.5, player.X, player.Y, true);

                             VisiblePoints.Add(new Point(x, y));
                        }                          
                    }
                    y--;
                }
                y++;
                break;

            case 5:

                y = player.Y + pDepth;
                if (y >= map.GetLength(1)) return;

                x = player.X + Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (x >= map.GetLength(0)) x = map.GetLength(0) - 1;

                while (GetSlope(x, y, player.X, player.Y, false) >= pEndSlope)
                {
                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (x + 1 < map.GetLength(1) && map[x+1, y] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x + 0.5, y - 0.5, player.X, player.Y, false));
                        }
                        else
                        {
                            if (x + 1 < map.GetLength(1)
                                    && map[x + 1, y] == 1)
                                pStartSlope = GetSlope(x + 0.5, y + 0.5, player.X, player.Y, false);

                            VisiblePoints.Add(new Point(x, y));
                        }
                    }
                    x--;
                }
                x++;
                break;

            case 6:

                y = player.Y + pDepth;
                if (y >= map.GetLength(1)) return;                  

                x = player.X - Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (x < 0) x = 0;

                while (GetSlope(x, y, player.X, player.Y, false) <= pEndSlope)
                {
                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (x - 1 >= 0 && map[x - 1, y] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x - 0.5, y - 0.5, player.X, player.Y, false));
                        }
                        else
                        {
                            if (x - 1 >= 0
                                    && map[x - 1, y] == 1)
                                pStartSlope = -GetSlope(x - 0.5, y + 0.5, player.X, player.Y, false);

                            VisiblePoints.Add(new Point(x, y));
                        }
                    }
                    x++;
                }
                x--;
                break;

            case 7:

                x = player.X - pDepth;
                if (x < 0) return;

                y = player.Y + Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));                    
                if (y >= map.GetLength(1)) y = map.GetLength(1) - 1;

                while (GetSlope(x, y, player.X, player.Y, true) <= pEndSlope)
                {

                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (y + 1 < map.GetLength(1) && map[x, y+1] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x + 0.5, y + 0.5, player.X, player.Y, true));
                        }
                        else
                        {
                            if (y + 1 < map.GetLength(1) && map[x, y + 1] == 1)
                                pStartSlope = -GetSlope(x - 0.5, y + 0.5, player.X, player.Y, true);

                            VisiblePoints.Add(new Point(x, y));
                        }
                    }
                    y--;
                }
                y++;
                break;

            case 8: //wnw

                x = player.X - pDepth;
                if (x < 0) return;

                y = player.Y - Convert.ToInt32((pStartSlope * Convert.ToDouble(pDepth)));
                if (y < 0) y = 0;

                while (GetSlope(x, y, player.X, player.Y, true) >= pEndSlope)
                {

                    if (GetVisDistance(x, y, player.X, player.Y) <= visrange2)
                    {

                        if (map[x, y] == 1)
                        {
                            if (y - 1 >=0 && map[x, y - 1] == 0)
                                ScanOctant(pDepth + 1, pOctant, pStartSlope, GetSlope(x + 0.5, y - 0.5, player.X, player.Y, true));

                        }
                        else
                        {
                            if (y - 1 >= 0 && map[x, y - 1] == 1)
                                pStartSlope = GetSlope(x - 0.5, y - 0.5, player.X, player.Y, true);

                            VisiblePoints.Add(new Point(x, y));
                        }
                    }
                    y++;
                }
                y--;
                break;
        }


        if (x < 0)
            x = 0;
        else if (x >= map.GetLength(0))
            x = map.GetLength(0) - 1;

        if (y < 0)
            y = 0;
        else if (y >= map.GetLength(1))
            y = map.GetLength(1) - 1;

        if (pDepth < VisualRange & map[x, y] == 0)
            ScanOctant(pDepth + 1, pOctant, pStartSlope, pEndSlope);

    }

    /// <summary>
    /// Get the gradient of the slope formed by the two points
    /// </summary>
    /// <param name="pX1"></param>
    /// <param name="pY1"></param>
    /// <param name="pX2"></param>
    /// <param name="pY2"></param>
    /// <param name="pInvert">Invert slope</param>
    /// <returns></returns>
    private double GetSlope(double pX1, double pY1, double pX2, double pY2, bool pInvert)
    {
        if (pInvert)
            return (pY1 - pY2) / (pX1 - pX2);
        else
            return (pX1 - pX2) / (pY1 - pY2);
    }


    /// <summary>
    /// Calculate the distance between the two points
    /// </summary>
    /// <param name="pX1"></param>
    /// <param name="pY1"></param>
    /// <param name="pX2"></param>
    /// <param name="pY2"></param>
    /// <returns>Distance</returns>
    private int GetVisDistance(int pX1, int pY1, int pX2, int pY2)
    {
        return ((pX1 - pX2) * (pX1 - pX2)) + ((pY1 - pY2) * (pY1 - pY2));
    }

    #endregion

ধন্যবাদ! দেখে মনে হচ্ছে এটি কোষগুলির মধ্যে প্রাচীরের সাথে কাজ করার জন্য এটি পেতে কৌশলযুক্ত হতে পারে তবে আমি এটিকে একবার দেখিয়ে দেব এবং এটি কীভাবে কাজ করে তা দেখুন!
রবার্ট ফ্রেজার

আমি অনুমতিপ্রাপ্ত অ্যালগরিদমগুলির সাথে যেতে চাই, কাগজের 8 ম পৃষ্ঠায় টেবিলটি দেখতে চাই
গুস্তাভো ম্যাকিয়েল

দুর্দান্ত কাগজ, যদিও আমার উপসংহারটি আলাদা হবে, কোনও ব্যবহারিক গতির পার্থক্য নেই। ফলাফলগুলি দেখায় যে সাধারণ দুর্বৃত্তের মতো মানচিত্রের জন্য, বেশিরভাগ অ্যালগরিদমগুলি 50 টি মাইক্রোসেকেন্ডের মধ্যে চলে, যার অর্থ বাস্তবে, আপনি গতি ব্যতীত অন্য মানদণ্ডের ভিত্তিতে বেছে নেওয়া ভাল।
কংগ্রেসবঙ্গাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.