public bool FindPath(Vec3 from, Vec3 to, MovementFlag flags, ref List <Vec3> path, float merge_distance = -1, bool as_close_as_possible = false, bool include_from = false, float random_coeff = 0, bool bounce = false, float shift_nodes_distance = 0, bool smoothen = true) { using (m_Navmesh.AcquireReadDataLock()) { List <path_pos> tmp_path = new List <path_pos>(); if (from.IsZero() || to.IsZero()) { return(false); } Cell start = null; Cell end = null; bool start_on_nav_mesh = m_Navmesh.GetCellContaining(from, out start, flags, false, as_close_as_possible, -1, false, 2, null); bool end_on_nav_mesh = m_Navmesh.GetCellContaining(to, out end, flags, false, as_close_as_possible, -1, false, 2, null); if (bounce) { Vec3 bounce_dir = start.AABB.GetBounceDir2D(from); Vec3 new_from = from + bounce_dir * 10; m_Navmesh.GetCellContaining(new_from, out start, flags, false, as_close_as_possible, -1, false, 2, null); if (!Algorihms.FindPath <Cell>(start, ref end, new_from, to, flags, ref tmp_path, random_coeff, true)) { return(false); } tmp_path.Insert(0, new path_pos(start.AABB.Align(from), start)); } else { if (!Algorihms.FindPath <Cell>(start, ref end, from, to, flags, ref tmp_path, random_coeff, true)) { return(false); } } if (smoothen && random_coeff == 0) { SmoothenPath(ref tmp_path, flags, bounce ? 1 : 0); } if (DistToKeepFromEdge > 0 && random_coeff == 0) { KeepAwayFromEdges(ref tmp_path, flags); } path = tmp_path.Select(x => x.pos).ToList(); PostProcessPath(ref path, merge_distance, shift_nodes_distance); if (!include_from && start_on_nav_mesh) { path.RemoveAt(0); } return(true); } }
public static List <Cell> GetCellsWithin(IEnumerable <Cell> cells, Vec3 p, float radius, MovementFlag flags, bool allow_disabled = false, bool test_2d = true, float z_tolerance = 0) { var result_cells = new List <Cell>(); if (p.IsZero()) { return(result_cells); } float radiusSqr = radius * radius; foreach (Cell cell in cells) { if ((!allow_disabled && cell.Disabled) || (cell.Flags & flags) != flags) { continue; } float distSqr = test_2d ? cell.Distance2DSqr(p) : cell.DistanceSqr(p); if (distSqr <= radiusSqr) { result_cells.Add(cell); } } return(result_cells); }
internal bool GetCellAt(Vec3 p, out ExploreCell result_cell) { using (new ReadLock(DataLock)) { result_cell = null; if (p.IsZero()) { return(false); } foreach (var explore_cell in m_ExploreCells) { if (explore_cell.Contains2D(p)) { var cells = explore_cell.GetCellsAt(p, test_2d: true, z_tolerance: 0); if (cells.Count() > 0) { result_cell = explore_cell; return(true); } } } return(false); } }
public NavMeshViewer(string[] args, Navmesh navmesh = null, NavigationEngine navigator = null, ExplorationEngine explorer = null) { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; BackColor = Color.LightGray; m_Params = new Params(args); m_Navmesh = navmesh; m_Navigator = navigator; m_Explorer = explorer; CreateNavigation(); LoadDebugConfig(); if (m_Params.HasParam("load")) { m_Params.GetParam("load", out string file); LoadData(file); } if (m_Params.HasParam("start")) { m_Params.GetParam("start", out string str); m_Navigator.CurrentPos = new Vec3(str); } if (m_Params.HasParam("end")) { m_Params.GetParam("end", out string str); m_Navigator.Destination = new destination(new Vec3(str)); } if (m_Params.HasParam("load_waypoints")) { m_Params.GetParam("load_waypoints", out string file); LoadWaypoints(file); } if (m_Params.HasParam("deserialize")) { m_Params.GetParam("deserialize", out string file); m_Navmesh.Deserialize(file); m_Navigator.Deserialize(file); m_Explorer.Deserialize(file); Vec3 initial_pos = m_Navigator.CurrentPos; if (initial_pos.IsZero()) { initial_pos = m_Navmesh.GetCenter(); } m_RenderCenter.X = initial_pos.X; m_RenderCenter.Y = initial_pos.Y; } InitializeComponents(); }
public static float GetPathLength(List <Vec3> path, Vec3 pos) { float length = 0; for (int i = 0; i < path.Count - 1; ++i) { length += path[i].Distance2D(path[i + 1]); } return(length + ((path.Count > 0 && !pos.IsZero()) ? path[0].Distance2D(pos) : 0)); }
private static void BuildPath <T>(T start, T end, Vec3 from, Vec3 to, NodeInfo info, ref List <path_pos> path) where T : Cell { // build result path if (path != null) { List <Cell> cells_list = new List <Cell>(); while (info != null) { cells_list.Add(info.cell); info = info.parent; } cells_list.Reverse(); for (int i = 0; i < cells_list.Count; ++i) { Cell cell = cells_list[i]; if (i == 0) { if (from.IsZero()) { path.Add(new path_pos(cell.Center, cell)); } else { path.Add(new path_pos(cell.AABB.Align(from), cell)); } } else { path.Add(new path_pos(cell.AABB.Align(path[path.Count - 1].pos), cell)); } if (i == cells_list.Count - 1) { if (to.IsZero()) { path.Add(new path_pos(cell.Center, cell)); } else { path.Add(new path_pos(cell.AABB.Align(to), cell)); } } } for (int k = path.Count - 2; k > 0; --k) { path[k] = new path_pos(path[k - 1].cell.AABB.Align(path[k + 1].pos), path[k].cell); } } }
private void LoadData(string filename, bool clear = true) { m_LastDataFile = filename; if (m_Navmesh.Load(filename, clear, true)) { Vec3 initial_pos = m_Navigator.CurrentPos; if (initial_pos.IsZero()) { initial_pos = m_Navmesh.GetCenter(); } m_RenderCenter.X = initial_pos.X; m_RenderCenter.Y = initial_pos.Y; } }
public bool FindRoughPath(Vec3 from, Vec3 to, ref List <Vec3> path) { if (from.IsZero() || to.IsZero()) { return(false); } List <path_pos> tmp_path = new List <path_pos>(); bool start_on_nav_mesh = GetCellAt(from, out ExploreCell start); bool end_on_nav_mesh = GetCellAt(to, out ExploreCell end); using (new ReadLock(DataLock)) Algorihms.FindPath(start, from, new Algorihms.DestinationPathFindStrategy <ExploreCell>(to, end), MovementFlag.None, ref tmp_path, use_cell_centers: true); path = tmp_path.Select(x => x.pos).ToList(); return(true); }
private void UpdateExploration() { Vec3 current_pos = m_Navigator.CurrentPos; if (current_pos.IsZero()) { return; } if (!IsDataAvailable) { m_Navmesh.Log("[Nav] Exploration data unavailable!"); return; } if (IsExplored()) { m_Navmesh.Log("[Nav] Exploration finished!"); m_Navigator.ClearDestination(DestType.Explore); return; } using (new ReadLock(DataLock, true)) { if (m_Navigator.GetDestinationType() < DestType.Explore) { m_DestCell = GetDestinationCell(); m_Navigator.SetDestination(GetDestinationCellPosition(), DestType.Explore, ExploreDestPrecision); //m_Navmesh.Log("[Nav] Explore dest changed."); } { // mark cells as explored when passing by close enough ExploreCell current_explore_cell = m_ExploreCells.FirstOrDefault(x => !x.Explored && x.Position.Distance2D(current_pos) < ExploreDestPrecision); if (current_explore_cell != null) { OnCellExplored(current_explore_cell); } } OnUpdateExploration(); } }
internal List <Cell> GetCellsWithin(Vec3 p, float radius, MovementFlag flags) { var result_cells = new List <Cell>(); if (p.IsZero()) { return(result_cells); } foreach (var cellsG in CellsGrid) { if (cellsG.Key.Distance2D(p) > radius) { continue; } result_cells.AddRange(Algorihms.GetCellsWithin(cellsG.Value, p, radius, flags, allow_disabled: true)); } return(result_cells); }
private void ReorganizeWaypoints() { Vec3 pos = CurrentPos; if (pos.IsZero()) { return; } using (new ReadLock(InputLock, true)) { if (m_Waypoints.Count == 0) { return; } int nearest_waypoint_index = -1; float nearest_waypoint_dist = float.MaxValue; for (int i = 0; i < m_Waypoints.Count; ++i) { float dist = m_Waypoints[i].Distance(pos); if (dist < nearest_waypoint_dist) { nearest_waypoint_index = i; nearest_waypoint_dist = dist; } } using (new WriteLock(InputLock)) { for (int i = 0; i < nearest_waypoint_index; ++i) { m_Waypoints.Add(new Vec3(m_Waypoints[0])); m_Waypoints.RemoveAt(0); } } } }
public static Cell GetCellAt(IEnumerable <Cell> cells, Vec3 p, MovementFlag flags, bool allow_disabled = false, bool test_2d = true, float z_tolerance = 0) { if (p.IsZero()) { return(null); } foreach (Cell cell in cells) { if ((!allow_disabled && cell.Disabled) || (cell.Flags & flags) != flags) { continue; } if (test_2d ? cell.Contains2D(p) : cell.Contains(p, z_tolerance)) { return(cell); } } return(null); }
private static void BuildPath <T>(T start, T end, Vec3 from, Vec3 to, NodeInfo info, ref List <path_pos> path, bool use_cell_centers = false) where T : Cell { // build result path if (path == null) { return; } List <Cell> cells_list = new List <Cell>(); if (info != null) { path.Add(new path_pos(to.IsZero() ? info.cell.Center : to, info.cell)); } while (info != null) { path.Add(new path_pos((use_cell_centers && info.parent != null) ? info.cell.Center : info.leading_point, info.cell)); info = info.parent; } path.Reverse(); }
protected virtual void OnKey(KeyEventArgs e) { if (e.Control) { if (e.KeyCode == Keys.D0) { m_RenderAxis = !m_RenderAxis; e.Handled = true; } if (e.KeyCode == Keys.D1) { m_RenderPath = !m_RenderPath; e.Handled = true; } else if (e.KeyCode == Keys.D2) { m_Navmesh.RegionsEnabled = !m_Navmesh.RegionsEnabled; e.Handled = true; } else if (e.KeyCode == Keys.D3) { m_RenderAvoidancePath = !m_RenderAvoidancePath; e.Handled = true; } else if (e.KeyCode == Keys.D4) { m_RenderPositionsHistory = !m_RenderPositionsHistory; e.Handled = true; } else if (e.KeyCode == Keys.D5) { m_RenderRoughPath = !m_RenderRoughPath; e.Handled = true; } } else { if (e.KeyCode == Keys.S) { Vec3 result = default(Vec3); if (!m_Navmesh.RayTrace(new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 1000), new Vec3(m_RenderCenter.X, m_RenderCenter.Y, -1000), MovementFlag.Walk, ref result)) { result = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); } m_Navigator.CurrentPos = result; e.Handled = true; } else if (e.KeyCode == Keys.E) { Vec3 result = default(Vec3); if (!m_Navmesh.RayTrace(new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 1000), new Vec3(m_RenderCenter.X, m_RenderCenter.Y, -1000), MovementFlag.Walk, ref result)) { result = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); } m_Navigator.SetCustomDestination(result); e.Handled = true; } else if (e.KeyCode == Keys.R) { Vec3 result = default(Vec3); if (!m_Navmesh.RayTrace(new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 1000), new Vec3(m_RenderCenter.X, m_RenderCenter.Y, -1000), MovementFlag.Walk, ref result)) { result = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); } m_Navigator.Destination = new destination(result, DestType.Custom, m_Navigator.DefaultPrecision, m_Navigator.DefaultPrecision * 2); e.Handled = true; } else if (e.KeyCode == Keys.L) { m_RenderLegend = !m_RenderLegend; e.Handled = true; } else if (e.KeyCode == Keys.D1) { m_RenderGrids = !m_RenderGrids; e.Handled = true; } else if (e.KeyCode == Keys.D2) { m_RenderCells = !m_RenderCells; e.Handled = true; } else if (e.KeyCode == Keys.D3) { m_RenderExploreCells = !m_RenderExploreCells; e.Handled = true; } else if (e.KeyCode == Keys.D4) { m_RenderConnections = !m_RenderConnections; e.Handled = true; } else if (e.KeyCode == Keys.D5) { m_RenderIds = !m_RenderIds; e.Handled = true; } else if (e.KeyCode == Keys.D6) { m_RenderConnected = !m_RenderConnected; e.Handled = true; } else if (e.KeyCode == Keys.D7) { m_RenderRegionsMode = (RegionsRenderMode)(((int)m_RenderRegionsMode + 1) % (int)RegionsRenderMode.Count); e.Handled = true; } else if (e.KeyCode == Keys.D8) { m_RenderOriginalPath = !m_RenderOriginalPath; e.Handled = true; } else if (e.KeyCode == Keys.D9) { m_RenderRayCast = !m_RenderRayCast; e.Handled = true; } else if (e.KeyCode == Keys.D0) { m_RenderBacktrackPath = !m_RenderBacktrackPath; e.Handled = true; } else if (e.KeyCode == Keys.F1) { LoadWaypoints(m_LastWaypointsFile); e.Handled = true; } else if (e.KeyCode == Keys.F2) { LoadData(m_LastDataFile ?? "nav_dump.txt"); e.Handled = true; } else if (e.KeyCode == Keys.F3) { m_Navmesh.Dump("nav_dump.txt"); e.Handled = true; } else if (e.KeyCode == Keys.F4) { m_Navmesh.Clear(); m_Navigator.Clear(); m_Explorer.Clear(); LoadDebugConfig(); e.Handled = true; } else if (e.KeyCode == Keys.F5) { m_Navmesh.Serialize("nav_save"); m_Navigator.Serialize("nav_save"); m_Explorer.Serialize("nav_save"); e.Handled = true; } else if (e.KeyCode == Keys.F6) { m_Navmesh.Deserialize("nav_save"); m_Navigator.Deserialize("nav_save"); m_Explorer.Deserialize("nav_save"); Vec3 initial_pos = m_Navigator.CurrentPos; if (initial_pos.IsZero()) { initial_pos = m_Navmesh.GetCenter(); } m_RenderCenter.X = initial_pos.X; m_RenderCenter.Y = initial_pos.Y; e.Handled = true; } else if (e.KeyCode == Keys.F7) { LoadDebugConfig(); e.Handled = true; } else if (e.KeyCode == Keys.F10) { //Thread t = new Thread(dbg_ContiniousSerialize); //t.Start(); Thread t = new Thread(() => dbg_MovingRegions(200)); t.Start(); e.Handled = true; } else if (e.KeyCode == Keys.F11) { m_Navmesh.dbg_GenerateRandomAvoidAreas(100, -1, 300, 2); e.Handled = true; } else if (e.KeyCode == Keys.B) { Vec3 result = default(Vec3); if (m_Navigator.CurrentPos.IsZero()) { m_Navmesh.RayTrace(new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 1000), new Vec3(m_RenderCenter.X, m_RenderCenter.Y, -1000), MovementFlag.Fly, ref result); } else { result = m_Navigator.CurrentPos; } m_Bot = new TestBot(m_Navmesh, m_Navigator, m_Explorer, result, m_BotSpeed); e.Handled = true; } else if (e.KeyCode == Keys.C) { m_CenterOnBot = !m_CenterOnBot; e.Handled = true; } else if (e.KeyCode == Keys.D) { if (m_Bot != null) { m_Bot.Destination = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); } e.Handled = true; } else if (e.KeyCode == Keys.H) { if (m_Explorer != null) { m_Explorer.HintPos = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); } e.Handled = true; } else if (e.KeyCode == Keys.X) { m_Navigator.CurrentPos = new Vec3(m_RenderCenter.X, m_RenderCenter.Y, 0); e.Handled = true; } else if (e.KeyCode == Keys.Space) { if (m_Bot != null) { m_Bot.Paused = !m_Bot.Paused; } e.Handled = true; } else if (e.KeyCode == Keys.V) { if (m_Bot != null) { m_Bot.BackTrace = !m_Bot.BackTrace; } e.Handled = true; } else if (e.KeyCode == Keys.P) { m_RenderPatches = !m_RenderPatches; e.Handled = true; } } }
private void UpdateExploration(bool forceReevaluation, bool ignore_explored) { Vec3 current_pos = m_Navigator.CurrentPos; if (current_pos.IsZero()) { return; } if (!IsDataAvailable) { m_Navmesh.Log("[Nav] Exploration data unavailable!"); return; } if (!ignore_explored && IsExplored()) { m_Navmesh.Log("[Nav] Exploration finished!"); m_Navigator.ClearDestination(DestType.Explore); return; } if (m_DestCell != null) { bool validate_dest_cell = Interlocked.CompareExchange(ref m_ValidateDestCell, 0, 1) == 1; bool mark_dest_cell_as_explored = false; // perform connection check only when reevaluation is forced (usually due to navigation data change) bool is_dest_cell_connected = (!forceReevaluation && !validate_dest_cell) || m_Navmesh.AreConnected(GetDestinationCellPosition(), current_pos, MovementFlag.Walk, 0, 0, out var unused1, out var unused2); // delay exploration of currently unconnected explore cells, unless they are already delayed (mark them as explored in that case) if (!is_dest_cell_connected) { if (!m_DestCell.Delayed) { m_DestCell.Delayed = true; forceReevaluation = true; // this is a change to find another un-delayed explore cell } else { // looks like there are no better cells to visit, and there is no way to reach this one... so sorry but we have to mark it as explored mark_dest_cell_as_explored = true; } } // mark destination cell as explored when external function says so or destination cell is no longer connected (mostly due to nav blocker) mark_dest_cell_as_explored |= AlternativeExploredCondition?.Invoke(m_DestCell, current_pos) ?? false; if (mark_dest_cell_as_explored) { Trace.WriteLine($"Explore cell GID {m_DestCell.GlobalId} considered explored by external logic."); OnCellExplored(m_DestCell); } } using (new ReadLock(DataLock, true)) { if ((Enabled && m_Navigator.GetDestinationType() < DestType.Explore) || (m_DestCell?.Explored ?? false) || forceReevaluation) { SelectNewDestinationCell(null); //m_Navmesh.Log("[Nav] Explore dest changed."); } ExploreCell travel_through_explore_cell = m_ExploreCells.FirstOrDefault(x => x.Contains2D(current_pos)); if (travel_through_explore_cell != null && !travel_through_explore_cell.Explored) { bool mark_explored = false; if (AlternativeExploredCondition?.Invoke(travel_through_explore_cell, current_pos) ?? false) { Trace.WriteLine($"Explore cell GID {travel_through_explore_cell.GlobalId} considered explored by external logic."); mark_explored = true; } // mark cells as explored when passing by close enough if (travel_through_explore_cell.Position.Distance2D(current_pos) < ExploreDestPrecision) { Trace.WriteLine($"Explore cell GID {travel_through_explore_cell.GlobalId} considered explored because of passing by."); mark_explored = true; } if (mark_explored) { OnCellExplored(travel_through_explore_cell); } } OnUpdateExploration(travel_through_explore_cell); } }
// Everything inside this method is rendered with transformation resulting from ModifyRenderMatrix. protected virtual void OnRenderData(PaintEventArgs e) { try { int cells_count = 0; int grid_cells_count = 0; if (m_RenderGrids || m_RenderCells) { using (m_Navmesh.AcquireReadDataLock()) { var grid_cells = m_Navmesh.dbg_GetGridCells(); if (m_RenderGrids) { foreach (Nav.GridCell grid_cell in grid_cells) { RenderHelper.Render(grid_cell, m_RenderCenter, e, m_RenderConnections, m_RenderIds); } grid_cells_count = grid_cells.Count; } if (m_RenderCells) { foreach (Nav.GridCell grid_cell in grid_cells) { foreach (Nav.Cell cell in grid_cell.GetCells()) { RenderHelper.Render(cell, m_RenderCenter, e, m_RenderConnections, m_RenderIds, m_RenderRegionsMode == RegionsRenderMode.MoveCostMult, m_RenderRegionsMode == RegionsRenderMode.Threat); } cells_count += grid_cell.GetCellsCount(); } } } } if (m_RenderExploreCells || m_RenderExploreArea) { using (m_Explorer.AquireReadDataLock()) { var explore_cells = m_Explorer.dbg_GetExploreCells(); foreach (Nav.ExploreCell explore_cell in explore_cells) { RenderHelper.Render(explore_cell, m_Explorer.ExploreDestPrecision, m_RenderCenter, e, m_RenderConnections, m_RenderIds); if (m_RenderExploreArea) { RenderHelper.DrawString(e.Graphics, explore_cell.Small ? Brushes.DarkRed : Brushes.Black, m_RenderCenter, explore_cell.Position, explore_cell.CellsArea().ToString(), 12); } } } } if (m_RenderPatches) { using (m_Navmesh.AcquireReadDataLock()) { int id = 0; foreach (var patch in m_Navmesh.m_CellsPatches) { var rng = new Random(id++); Color c = Color.FromArgb(rng.Next(255), rng.Next(255), rng.Next(255)); foreach (var cell in patch.Cells) { RenderHelper.Render(cell, m_RenderCenter, e, draw_connections: false, draw_id: false, render_move_cost_mult: false, render_threat: false, render_outline: false, render_disabled: true, force_color: c); } } } } if (m_RenderRegionsMode == RegionsRenderMode.Outline) { var regions = m_Navmesh.Regions; foreach (var region in regions) { RenderHelper.DrawRectangle(e.Graphics, Pens.Black, m_RenderCenter, region.Area.Min, region.Area.Max); } //Vec3 safe_point = m_Navigator.GetNearestGridCellOutsideAvoidAreas(); //if (!safe_point.IsEmpty) // RenderHelper.DrawPoint(e.Graphics, Pens.Green, render_center, safe_point); } if (m_RenderAxis) { e.Graphics.DrawString("X", new Font("Arial", 6 / m_RenderScale), Brushes.Black, 25 / m_RenderScale, 0); e.Graphics.DrawLine(RenderHelper.AXIS_PEN, -25 / m_RenderScale, 0, 25 / m_RenderScale, 0); e.Graphics.DrawString("Y", new Font("Arial", 6 / m_RenderScale), Brushes.Black, 0, 25 / m_RenderScale); e.Graphics.DrawLine(RenderHelper.AXIS_PEN, 0, -25 / m_RenderScale, 0, 25 / m_RenderScale); } if (!m_RenderOriginalPath && m_RenderPath) { destination last_path_dest = default(destination); if (m_Navigator.TryGetPath(ref m_LastPath, ref last_path_dest)) { m_LastPath.Insert(0, m_Navigator.CurrentPos); } RenderHelper.DrawLines(e.Graphics, RenderHelper.PATH_PEN, m_RenderCenter, m_LastPath, 1, true); if (!m_Navigator.PathRecalcTriggerPosition.IsZero()) { RenderHelper.DrawCircle(e.Graphics, Pens.DarkRed, m_RenderCenter, m_Navigator.PathRecalcTriggerPosition, m_Navigator.PathRecalcTriggerPrecision); } } if (m_RenderBacktrackPath) { if (m_Navigator.TryGetBackTrackPath(ref m_LastBacktrackPath)) { m_LastBacktrackPath.Insert(0, m_Navigator.CurrentPos); } RenderHelper.DrawLines(e.Graphics, Pens.Blue, m_RenderCenter, m_LastBacktrackPath, 1); } if (m_RenderPositionsHistory) { m_Navigator.TryGetDebugPositionsHistory(ref m_LastPositionsHistory); RenderHelper.DrawLines(e.Graphics, Pens.Green, m_RenderCenter, m_LastPositionsHistory, 1, true); } Vec3 curr = m_Navigator.CurrentPos; Vec3 dest = m_Navigator.Destination.pos; var ring_dest = m_Navigator.RingDestination; if (!curr.IsZero()) { RenderHelper.DrawPoint(e.Graphics, Pens.Blue, m_RenderCenter, curr); } if (!dest.IsZero()) { RenderHelper.DrawPoint(e.Graphics, Pens.LightBlue, m_RenderCenter, dest); } if (!ring_dest.pos.IsZero()) { RenderHelper.DrawPoint(e.Graphics, Pens.LightBlue, m_RenderCenter, ring_dest.pos); RenderHelper.DrawCircle(e.Graphics, Pens.LightBlue, m_RenderCenter, ring_dest.pos, ring_dest.precision); RenderHelper.DrawCircle(e.Graphics, Pens.LightBlue, m_RenderCenter, ring_dest.pos, ring_dest.precision_max); } if (!curr.IsZero() && !dest.IsZero()) { if (m_RenderOriginalPath) { List <Vec3> path = new List <Vec3>(); m_Navigator.FindPath(curr, dest, MovementFlag.Walk, ref path, out var path_recalc_trigger_position, out var path_recalc_trigger_precision, -1, false, false, 0, false, 0, smoothen_distance: 0); path.Insert(0, curr); RenderHelper.DrawLines(e.Graphics, Pens.Black, m_RenderCenter, path, 1); } if (m_RenderRoughPath) { List <Vec3> rought_path = new List <Vec3>(); if (m_Navigator.m_RoughtPathEstimator != null) { m_Navigator.m_RoughtPathEstimator.FindRoughPath(curr, dest, ref rought_path); } rought_path.Insert(0, curr); RenderHelper.DrawLines(e.Graphics, RenderHelper.EXPLORE_PATH_PEN, m_RenderCenter, rought_path, 1, true); } if (m_RenderRayCast) { var result = m_Navmesh.RayCast2D(curr, dest, MovementFlag.Walk); RenderHelper.DrawLine(e.Graphics, result ? Pens.Green : Pens.Red, m_RenderCenter, curr, result.End); } if (m_RenderConnected) { bool connected = m_Navmesh.AreConnected(curr, dest, MovementFlag.Walk, 100, 400, out var curr_on_nav, out var dest_on_nav); RenderHelper.DrawLine(e.Graphics, connected ? Pens.Green : Pens.Red, m_RenderCenter, curr, dest); RenderHelper.DrawLine(e.Graphics, Pens.Lavender, m_RenderCenter, curr, curr_on_nav); RenderHelper.DrawLine(e.Graphics, Pens.Lavender, m_RenderCenter, dest, dest_on_nav); RenderHelper.DrawString(e.Graphics, connected ? Brushes.Green : Brushes.Red, m_RenderCenter, dest, connected ? "connected" : "not connected", 4); } } if (!curr.IsZero() && dest.IsZero()) { if (m_RenderAvoidancePath) { List <Vec3> path = new List <Vec3>(); m_Navigator.FindAvoidancePath(curr, 0, MovementFlag.Walk, ref path, Vec3.ZERO, false, 0, float.MaxValue); path.Insert(0, curr); RenderHelper.DrawLines(e.Graphics, Pens.Black, m_RenderCenter, path, 1); } } var waypoints = m_Navigator.Waypoints; if (waypoints.Count > 0) { RenderHelper.DrawLines(e.Graphics, Pens.Red, m_RenderCenter, waypoints, 1); } if (m_Bot != null) { //if (!m_Bot.Paused && m_CenterOnBot) // m_RenderCenter = new PointF(m_Bot.Position.X, m_Bot.Position.Y); m_Bot.Render(e.Graphics, m_RenderCenter); } } catch (Exception) { } }
// Everything inside this method is rendered with transformation resulting from ModifyRenderMatrix. protected virtual void OnRenderData(PaintEventArgs e) { try { int cells_count = 0; int grid_cells_count = 0; if (m_RenderGrids || m_RenderCells) { using (m_Navmesh.AcquireReadDataLock()) { var grid_cells = m_Navmesh.dbg_GetGridCells(); if (m_RenderGrids) { foreach (Nav.GridCell grid_cell in grid_cells) { RenderHelper.Render(grid_cell, m_RenderCenter, e, m_RenderConnections, m_RenderIds); } grid_cells_count = grid_cells.Count; } if (m_RenderCells) { foreach (Nav.GridCell grid_cell in grid_cells) { foreach (Nav.Cell cell in grid_cell.GetCells()) { RenderHelper.Render(cell, m_RenderCenter, e, m_RenderConnections, m_RenderIds, m_RenderRegionsMode == RegionsRenderMode.MoveCostMult, m_RenderRegionsMode == RegionsRenderMode.Threat); } cells_count += grid_cell.GetCellsCount(); } } } } if (m_RenderExploreCells || m_RenderExploreArea) { using (m_Explorer.AquireReadDataLock()) { var explore_cells = m_Explorer.dbg_GetExploreCells(); foreach (Nav.ExploreCell explore_cell in explore_cells) { RenderHelper.Render(explore_cell, m_Explorer.ExploreDestPrecision, m_RenderCenter, e, m_RenderConnections, m_RenderIds); if (m_RenderExploreArea) { RenderHelper.DrawString(e.Graphics, Brushes.Black, m_RenderCenter, explore_cell.Position, explore_cell.CellsArea().ToString(), 5); } } } } if (m_RenderRegionsMode == RegionsRenderMode.Outline) { var regions = m_Navmesh.Regions; foreach (var region in regions) { RenderHelper.DrawRectangle(e.Graphics, Pens.Black, m_RenderCenter, region.Area.Min, region.Area.Max); } //Vec3 safe_point = m_Navigator.GetNearestGridCellOutsideAvoidAreas(); //if (!safe_point.IsEmpty) // RenderHelper.DrawPoint(e.Graphics, Pens.Green, render_center, safe_point); } if (m_RenderAxis) { e.Graphics.DrawString("X", new Font("Arial", 6 / m_RenderScale), Brushes.Black, 25 / m_RenderScale, 0); e.Graphics.DrawLine(RenderHelper.AXIS_PEN, -25 / m_RenderScale, 0, 25 / m_RenderScale, 0); e.Graphics.DrawString("Y", new Font("Arial", 6 / m_RenderScale), Brushes.Black, 0, 25 / m_RenderScale); e.Graphics.DrawLine(RenderHelper.AXIS_PEN, 0, -25 / m_RenderScale, 0, 25 / m_RenderScale); } if (!m_RenderOriginalPath && m_RenderPath) { DestType last_path_dest_type = DestType.None; if (m_Navigator.TryGetPath(ref m_LastPath, ref last_path_dest_type)) { m_LastPath.Insert(0, m_Navigator.CurrentPos); } RenderHelper.DrawLines(e.Graphics, RenderHelper.PATH_PEN, m_RenderCenter, m_LastPath, 1, true); } if (m_RenderBacktrackPath) { if (m_Navigator.TryGetBackTrackPath(ref m_LastBacktrackPath)) { m_LastBacktrackPath.Insert(0, m_Navigator.CurrentPos); } RenderHelper.DrawLines(e.Graphics, Pens.Blue, m_RenderCenter, m_LastBacktrackPath, 1); } if (m_RenderPositionsHistory) { m_Navigator.TryGetDebugPositionsHistory(ref m_LastPositionsHistory); RenderHelper.DrawLines(e.Graphics, Pens.Green, m_RenderCenter, m_LastPositionsHistory, 1); } Vec3 curr = m_Navigator.CurrentPos; Vec3 dest = m_Navigator.Destination; if (!curr.IsZero()) { RenderHelper.DrawPoint(e.Graphics, Pens.Blue, m_RenderCenter, curr); } if (!dest.IsZero()) { RenderHelper.DrawPoint(e.Graphics, Pens.LightBlue, m_RenderCenter, dest); } if (!curr.IsZero() && !dest.IsZero()) { if (m_RenderOriginalPath) { List <Vec3> path = new List <Vec3>(); m_Navigator.FindPath(curr, dest, MovementFlag.Walk, ref path, -1, false, false, 0, false, 0, false); path.Insert(0, curr); RenderHelper.DrawLines(e.Graphics, Pens.Black, m_RenderCenter, path, 1); } if (m_RenderRayCast) { var result = m_Navmesh.RayCast2D(curr, dest, MovementFlag.Walk); RenderHelper.DrawLine(e.Graphics, result ? Pens.Green : Pens.Red, m_RenderCenter, curr, result.End); } if (m_RenderConnected) { bool connected = m_Navmesh.AreConnected(curr, dest, MovementFlag.Walk, 40); RenderHelper.DrawLine(e.Graphics, connected ? Pens.Green : Pens.Red, m_RenderCenter, curr, dest); RenderHelper.DrawString(e.Graphics, connected ? Brushes.Green : Brushes.Red, m_RenderCenter, dest, connected ? "connected" : "not connected", 4); } } if (!curr.IsZero() && dest.IsZero()) { if (m_RenderAvoidancePath) { List <Vec3> path = new List <Vec3>(); m_Navigator.FindAvoidancePath(curr, 0, MovementFlag.Walk, ref path, Vec3.ZERO, false, 0, true); path.Insert(0, curr); RenderHelper.DrawLines(e.Graphics, Pens.Black, m_RenderCenter, path, 1); } } var waypoints = m_Navigator.Waypoints; if (waypoints.Count > 0) { RenderHelper.DrawLines(e.Graphics, Pens.Red, m_RenderCenter, waypoints, 1); } if (m_Bot != null) { //if (!m_Bot.Paused && m_CenterOnBot) // m_RenderCenter = new PointF(m_Bot.Position.X, m_Bot.Position.Y); m_Bot.Render(e.Graphics, m_RenderCenter); } } catch (Exception) { } }
private void UpdateExploration() { Vec3 current_pos = m_Navigator.CurrentPos; if (current_pos.IsZero()) { return; } if (!IsDataAvailable) { m_Navmesh.Log("[Nav] Exploration data unavailable!"); return; } if (IsExplored()) { m_Navmesh.Log("[Nav] Exploration finished!"); m_Navigator.ClearDestination(DestType.Explore); return; } if (m_DestCell != null) { bool mark_dest_cell_as_explored = false; // perform connection check only when reevaluation is forced (usually due to navigation data change) bool is_dest_cell_connected = (!m_ForceReevaluation && !m_ValidateDestCell) || m_Navmesh.AreConnected(GetDestinationCellPosition(), current_pos, MovementFlag.Walk, ExploreDestPrecision, 0, out var unused1, out var unused2); // delay exploration of currently unconnected explore cells, unless they are already delayed (mark them as explored in that case) if (!is_dest_cell_connected) { if (!m_DestCell.Delayed) { m_DestCell.Delayed = true; m_ForceReevaluation = true; // this is a change to find another un-delayed explore cell } else { // looks like there are no better cells to visit, and there is no way to reach this one... so sorry but we have to mark it as explored mark_dest_cell_as_explored = true; } } m_ValidateDestCell = false; // mark destination cell as explored when external function says so or destination cell is no longer connected (mostly due to nav blocker) mark_dest_cell_as_explored |= AlternativeExploredCondition?.Invoke(m_DestCell, current_pos) ?? false; if (mark_dest_cell_as_explored) { OnCellExplored(m_DestCell); } } using (new ReadLock(DataLock, true)) { if (m_Navigator.GetDestinationType() < DestType.Explore || (m_DestCell?.Explored ?? false) || m_ForceReevaluation) { SelectNewDestinationCell(); //m_Navmesh.Log("[Nav] Explore dest changed."); } // mark cells as explored when passing by close enough ExploreCell current_explore_cell = m_ExploreCells.FirstOrDefault(x => !x.Explored && x.Position.Distance2D(current_pos) < ExploreDestPrecision); if (current_explore_cell != null) { OnCellExplored(current_explore_cell); } OnUpdateExploration(); } }