How to deal with the new tiles type (unsafe span)? Removing nodes marked as unwalkable

In case this is useful to anyone else here is the full code. This is a helper for removing unwanted areas from tiled recast graphs.

using System.Collections.Generic;
using UnityEngine;

namespace Pathfinding
{
    public class PathRemoveUnconnected : GraphModifier
    {
        // Remove unconnected areas in tiled recast graphs that are not relevant
        // After graphs are scanned, this will mark all nodes that are not relevant as not walkable and then remove them
        // Desired functionality is similar to relevantGraphSurface but without having to place objects in each tile
        // Usage: place an empty GameObject inside areas you want to keep and add these to the areaMarkers array

        public Transform[] areaMarkers;
        Vector3[] connectedPoints;
        HashSet<GraphNode> connectedNodes = new HashSet<GraphNode>();
        List<GraphNode> toSearch = new List<GraphNode>();
        GraphNode nearestNode;
        GraphNode searchNode;
        int removedNodeCounter;

        public override void OnPostScan()
        {
            Debug.Log("Graphs-->OnPostScan");
            // Get connected points from area markers
            connectedPoints = new Vector3[areaMarkers.Length];
            for (int x = 0; x < areaMarkers.Length; x++) {
                connectedPoints[x] = areaMarkers[x].transform.position;
            }
            // Create a list of the recast graphs in scene
            List<RecastGraph> recastGraphs = new List<RecastGraph>();
            foreach (RecastGraph r in AstarPath.active.data.FindGraphsOfType(typeof(RecastGraph))) {
                recastGraphs.Add(r);
            }
            if (recastGraphs.Count == 0) return;
            // Process each graph
            toSearch.Clear();
            connectedNodes.Clear();
            for (int r = 0; r < recastGraphs.Count; r++) {
                // Get the nearest node to each area marker and add to the search
                for (int x = 0; x < connectedPoints.Length; x++) {
                    nearestNode = recastGraphs[r].GetNearest(connectedPoints[x], NNConstraint.Walkable).node;
                    if (nearestNode != null) {
                        connectedNodes.Add(nearestNode);
                        toSearch.Add(nearestNode);
                    }
                }
                // Go through all connected nodes and add them to the connected list
                while (toSearch.Count > 0) {
                    searchNode = toSearch[toSearch.Count - 1];
                    toSearch.RemoveAt(toSearch.Count - 1);
                    searchNode.GetConnections(n =>
                    {
                        if (n.Walkable && !connectedNodes.Contains(n)) {
                            toSearch.Add(n);
                            connectedNodes.Add(n);
                        }
                    });
                }
                // Mark unconnected nodes as not walkable
                recastGraphs[r].GetNodes(node =>
                {
                    if (!connectedNodes.Contains(node)) {
                        node.Walkable = false;
                        node.ClearConnections(true);
                    }
                });
                // Update each tile and discard non walkable nodes
                removedNodeCounter = 0;
                recastGraphs[r].StartBatchTileUpdate();
                foreach (var tile in recastGraphs[r].GetTiles()) {
                    var trianglesToKeep = new List<int>();
                    for (int i = 0; i < tile.nodes.Length; i++) {
                        var node = tile.nodes[i];
                        if (node.Walkable) {
                            trianglesToKeep.Add(tile.tris[i * 3 + 0]);
                            trianglesToKeep.Add(tile.tris[i * 3 + 1]);
                            trianglesToKeep.Add(tile.tris[i * 3 + 2]);
                        }
                        else {
                            removedNodeCounter++;
                        }
                    }
                    var offset = (Int3)new Vector3((tile.x * recastGraphs[r].TileWorldSizeX), 0, (tile.z * recastGraphs[r].TileWorldSizeZ));
                    Int3[] newVerts = new Int3[tile.verts.Length];
                    for (int i = 0; i < tile.verts.Length; i++) {
                        newVerts[i] = tile.vertsInGraphSpace[i] - offset;
                    }
                    recastGraphs[r].ReplaceTile(tile.x, tile.z, newVerts, trianglesToKeep.ToArray());
                }
                recastGraphs[r].EndBatchTileUpdate();
                // Info
                Debug.Log("Graph #" + r + ", Tile count: " + recastGraphs[r].GetTiles().Length + ", Nodes removed: " + removedNodeCounter);
            }
        }
    }
}
3 Likes