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)); }
public PixelDist(Pixel px, float dist) { this.px = px; this.dist = dist; }