Exemplo n.º 1
0
        CostMap ComputeCostMap(float allow_wall_ground_dist, bool no_wall_clip, bool targetBonus)
        {
            // Simple Dijkstra algorithm with some extra parameters.
            // Ground wall bonus is not applied during the Dijkstra algorithm because it would generate negative weights.
            // Instead, it will be applied after, when asking a specific cost, to each pixel in collision (proportionally if current weight is smaller than gwb min dist).

            float wgm_dist   = Settings.wall_clip_malus_dist < 1 ? 1 : Settings.wall_clip_malus_dist;
            float wgm_per_px = Settings.wall_clip_malus / wgm_dist;

            int width  = PixelEnd.x - PixelStart.x + 1;
            int height = PixelEnd.y - PixelStart.y + 1;

            float[,] res = new float[height, width];
            SimplePriorityQueue <Pixel> q = new SimplePriorityQueue <Pixel>();

            // Init target
            bool[,] target;
            if (targetBonus)
            {
                target = new bool[height, width];
                for (short y = PixelStart.y; y <= PixelEnd.y; y++)
                {
                    for (short x = PixelStart.x; x <= PixelEnd.x; x++)
                    {
                        target[y - PixelStart.y, x - PixelStart.x] = m.IsPixelInBonus(x, y) != Map.BonusType.None;
                    }
                }
            }
            else
            {
                target = this.target;
                if (target == null)
                {
                    target = new bool[height, width];
                    for (short y = PixelStart.y; y <= PixelEnd.y; y++)
                    {
                        for (short x = PixelStart.x; x <= PixelEnd.x; x++)
                        {
                            target[y - PixelStart.y, x - PixelStart.x] = m.IsPixelInZone(x, y) == Map.Zone.Ending;
                        }
                    }
                }
            }

            // Init
            for (short y = PixelStart.y; y <= PixelEnd.y; y++)
            {
                for (short x = PixelStart.x; x <= PixelEnd.x; x++)
                {
                    if (target[y - PixelStart.y, x - PixelStart.x])
                    {
                        q.Enqueue(new Pixel(x, y), 0);
                        res[y - PixelStart.y, x - PixelStart.x] = 0;
                    }
                    else
                    {
                        res[y - PixelStart.y, x - PixelStart.x] = float.PositiveInfinity;
                    }
                }
            }

            // Dijkstra
            while (q.Count > 0)
            {
                Pixel p                    = q.Dequeue();
                float weight               = res[p.y - PixelStart.y, p.x - PixelStart.x];
                float from_wall_dist       = dist_to_wall[p.y - PixelStart.y, p.x - PixelStart.x];
                bool  from_wall            = from_wall_dist <= 0;
                bool  from_wc_allowed_zone = from_wall_dist <= allow_wall_ground_dist;
                bool  from_healzone        = IsHealZone(p.x, p.y);

                PixelDist[] neighbors = Neighbors(p);
                foreach (PixelDist npd in neighbors)
                {
                    int npy = npd.px.y - PixelStart.y;
                    int npx = npd.px.x - PixelStart.x;

                    if (constraints != null && constraints[npy, npx])
                    {
                        continue;
                    }

                    float to_wall_dist       = dist_to_wall[npy, npx];
                    bool  to_wall            = to_wall_dist <= 0;
                    bool  to_wc_allowed_zone = to_wall_dist <= allow_wall_ground_dist;
                    bool  to_legal_zone      = legal_zones[npy, npx];
                    bool  to_healzone        = IsHealZone(npd.px.x, npd.px.y);

                    float wgm = Math.Min(to_wall_dist, wgm_dist) - from_wall_dist;
                    if (wgm <= 0)
                    {
                        wgm = 0;
                    }
                    else
                    {
                        wgm *= wgm_per_px;
                    }

                    if (no_wall_clip && to_wall)
                    {
                        continue;
                    }

                    if (Settings.cwc_max_dist_zero_in_legal_zone && allow_wall_ground_dist < float.PositiveInfinity && to_legal_zone)
                    {
                        from_wc_allowed_zone = from_wall;
                        to_wc_allowed_zone   = to_wall;
                    }

                    float nw = weight;
                    if (from_wc_allowed_zone && !to_wc_allowed_zone)
                    {
                        nw = float.PositiveInfinity;
                    }
                    else if (from_wall && to_wall)
                    {
                        nw += npd.dist / Settings.wall_speed;
                    }
                    else
                    {
                        nw += npd.dist / Settings.ground_speed + wgm;
                    }

                    if (from_healzone && !to_healzone)
                    {
                        nw += Settings.damageless_back_before_healzone_malus;
                    }

                    float ow = res[npy, npx];
                    if (nw < ow)
                    {
                        res[npy, npx] = nw;
                        if (ow < float.PositiveInfinity)
                        {
                            q.UpdatePriority(npd.px, nw);
                        }
                        else
                        {
                            q.Enqueue(npd.px, nw);
                        }
                    }
                }
            }

            // Post-procedure (some post-procedure has been moved to the CostMap class)
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    float w = res[y, x];
                    // Healzone bonus
                    if (IsHealZone((short)(x + PixelStart.x), (short)(y + PixelStart.y)))
                    {
                        w -= Settings.damageless_healzone_bonus;
                    }

                    if (w <= 0 && !target[y, x])
                    {
                        w = float.Epsilon;
                    }
                    else if (w < 0)
                    {
                        w = 0;
                    }
                    res[y, x] = w;
                }
            }

            return(new CostMap(res, dist_to_wall, PixelStart, !no_wall_clip));
        }
Exemplo n.º 2
0
 public PixelDist(Pixel px, float dist)
 {
     this.px   = px;
     this.dist = dist;
 }