// Token: 0x0600265C RID: 9820 RVA: 0x001A99D0 File Offset: 0x001A7BD0 public void RecalculatePivots() { if (this.mode == HeuristicOptimizationMode.None) { this.pivotCount = 0; this.pivots = null; return; } this.rval = (uint)this.seed; List<GraphNode> list = ListPool<GraphNode>.Claim(); switch (this.mode) { case HeuristicOptimizationMode.Random: this.PickNRandomNodes(this.spreadOutCount, list); break; case HeuristicOptimizationMode.RandomSpreadOut: { if (this.pivotPointRoot != null) { this.GetClosestWalkableNodesToChildrenRecursively(this.pivotPointRoot, list); } if (list.Count == 0) { GraphNode graphNode = this.PickAnyWalkableNode(); if (graphNode == null) { Debug.LogError("Could not find any walkable node in any of the graphs."); ListPool<GraphNode>.Release(ref list); return; } list.Add(graphNode); } int num = this.spreadOutCount - list.Count; for (int i = 0; i < num; i++) { list.Add(null); } break; } case HeuristicOptimizationMode.Custom: if (this.pivotPointRoot == null) { throw new Exception("heuristicOptimizationMode is HeuristicOptimizationMode.Custom, but no 'customHeuristicOptimizationPivotsRoot' is set"); } this.GetClosestWalkableNodesToChildrenRecursively(this.pivotPointRoot, list); break; default: throw new Exception("Invalid HeuristicOptimizationMode: " + this.mode); } this.pivots = list.ToArray(); ListPool<GraphNode>.Release(ref list); }
private void AddGraphObstacles(Simulator sim, INavmesh ng) { int[] uses = new int[3]; Dictionary <int, int> outline = new Dictionary <int, int>(); Dictionary <int, Int3> vertexPositions = new Dictionary <int, Int3>(); HashSet <int> hasInEdge = new HashSet <int>(); ng.GetNodes(delegate(GraphNode _node) { TriangleMeshNode triangleMeshNode = _node as TriangleMeshNode; uses[0] = (uses[1] = (uses[2] = 0)); if (triangleMeshNode != null) { for (int i = 0; i < triangleMeshNode.connections.Length; i++) { TriangleMeshNode triangleMeshNode2 = triangleMeshNode.connections[i].node as TriangleMeshNode; if (triangleMeshNode2 != null) { int num = triangleMeshNode.SharedEdge(triangleMeshNode2); if (num != -1) { uses[num] = 1; } } } for (int j = 0; j < 3; j++) { if (uses[j] == 0) { int i2 = j; int i3 = (j + 1) % triangleMeshNode.GetVertexCount(); outline[triangleMeshNode.GetVertexIndex(i2)] = triangleMeshNode.GetVertexIndex(i3); hasInEdge.Add(triangleMeshNode.GetVertexIndex(i3)); vertexPositions[triangleMeshNode.GetVertexIndex(i2)] = triangleMeshNode.GetVertex(i2); vertexPositions[triangleMeshNode.GetVertexIndex(i3)] = triangleMeshNode.GetVertex(i3); } } } }); List <Vector3> vertices = ListPool <Vector3> .Claim(); RVONavmesh.CompressContour(outline, hasInEdge, delegate(List <int> chain, bool cycle) { for (int i = 0; i < chain.Count; i++) { vertices.Add((Vector3)vertexPositions[chain[i]]); } this.obstacles.Add(sim.AddObstacle(vertices.ToArray(), this.wallHeight, cycle)); vertices.Clear(); }); ListPool <Vector3> .Release(vertices); }
public void BuildFunnelCorridor(List <GraphNode> nodes, int start, int end) { this.exactStart = (nodes[start] as MeshNode).ClosestPointOnNode(this.exactStart); this.exactEnd = (nodes[end] as MeshNode).ClosestPointOnNode(this.exactEnd); this.left.Clear(); this.right.Clear(); this.left.Add(this.exactStart); this.right.Add(this.exactStart); this.nodes.Clear(); IRaycastableGraph raycastableGraph = this.graph as IRaycastableGraph; if (raycastableGraph != null && this.funnelSimplification) { List <GraphNode> list = ListPool <GraphNode> .Claim(end - start); this.SimplifyPath(raycastableGraph, nodes, start, end, list, this.exactStart, this.exactEnd); if (this.nodes.Capacity < list.Count) { this.nodes.Capacity = list.Count; } for (int i = 0; i < list.Count; i++) { TriangleMeshNode triangleMeshNode = list[i] as TriangleMeshNode; if (triangleMeshNode != null) { this.nodes.Add(triangleMeshNode); } } ListPool <GraphNode> .Release(list); } else { if (this.nodes.Capacity < end - start) { this.nodes.Capacity = end - start; } for (int j = start; j <= end; j++) { TriangleMeshNode triangleMeshNode2 = nodes[j] as TriangleMeshNode; if (triangleMeshNode2 != null) { this.nodes.Add(triangleMeshNode2); } } } for (int k = 0; k < this.nodes.Count - 1; k++) { this.nodes[k].GetPortal(this.nodes[k + 1], this.left, this.right, false); } this.left.Add(this.exactEnd); this.right.Add(this.exactEnd); }
public void CollectRecastMeshObjs(List <RasterizationMesh> buffer) { List <RecastMeshObj> list = ListPool <RecastMeshObj> .Claim(); RecastMeshObj.GetAllInBounds(list, this.bounds); Dictionary <Mesh, Vector3[]> dictionary = new Dictionary <Mesh, Vector3[]>(); Dictionary <Mesh, int[]> dictionary2 = new Dictionary <Mesh, int[]>(); for (int i = 0; i < list.Count; i++) { MeshFilter meshFilter = list[i].GetMeshFilter(); Renderer renderer = (meshFilter != null) ? meshFilter.GetComponent <Renderer>() : null; if (meshFilter != null && renderer != null) { Mesh sharedMesh = meshFilter.sharedMesh; RasterizationMesh rasterizationMesh; if (dictionary.ContainsKey(sharedMesh)) { rasterizationMesh = new RasterizationMesh(dictionary[sharedMesh], dictionary2[sharedMesh], renderer.bounds); } else { rasterizationMesh = new RasterizationMesh(sharedMesh.vertices, sharedMesh.triangles, renderer.bounds); dictionary[sharedMesh] = rasterizationMesh.vertices; dictionary2[sharedMesh] = rasterizationMesh.triangles; } rasterizationMesh.matrix = renderer.localToWorldMatrix; rasterizationMesh.original = meshFilter; rasterizationMesh.area = list[i].area; buffer.Add(rasterizationMesh); } else { Collider collider = list[i].GetCollider(); if (collider == null) { Debug.LogError("RecastMeshObject (" + list[i].gameObject.name + ") didn't have a collider or MeshFilter+Renderer attached", list[i].gameObject); } else { RasterizationMesh rasterizationMesh2 = this.RasterizeCollider(collider); if (rasterizationMesh2 != null) { rasterizationMesh2.area = list[i].area; buffer.Add(rasterizationMesh2); } } } } this.capsuleCache.Clear(); ListPool <RecastMeshObj> .Release(list); }
public List <Vector3> SmoothBezier(List <Vector3> path) { if (subdivisions < 0) { subdivisions = 0; } int subMult = 1 << subdivisions; List <Vector3> subdivided = ListPool <Vector3> .Claim(); for (int i = 0; i < path.Count - 1; i++) { Vector3 tangent1; Vector3 tangent2; if (i == 0) { tangent1 = path[i + 1] - path[i]; } else { tangent1 = path[i + 1] - path[i - 1]; } if (i == path.Count - 2) { tangent2 = path[i] - path[i + 1]; } else { tangent2 = path[i] - path[i + 2]; } tangent1 *= bezierTangentLength; tangent2 *= bezierTangentLength; Vector3 v1 = path[i]; Vector3 v2 = v1 + tangent1; Vector3 v4 = path[i + 1]; Vector3 v3 = v4 + tangent2; for (int j = 0; j < subMult; j++) { subdivided.Add(AstarMath.CubicBezier(v1, v2, v3, v4, (float)j / subMult)); } } //Assign the last point subdivided.Add(path[path.Count - 1]); return(subdivided); }
/// <summary> /// Returns all nodes reachable from the seed node. /// This function performs a DFS (depth-first-search) or flood fill of the graph and returns all nodes which can be reached from /// the seed node. In almost all cases this will be identical to returning all nodes which have the same area as the seed node. /// In the editor areas are displayed as different colors of the nodes. /// The only case where it will not be so is when there is a one way path from some part of the area to the seed node /// but no path from the seed node to that part of the graph. /// /// The returned list is not sorted in any particular way. /// /// Depending on the number of reachable nodes, this function can take quite some time to calculate /// so don't use it too often or it might affect the framerate of your game. /// /// See: bitmasks (view in online documentation for working links). /// /// Returns: A List<Node> containing all nodes reachable from the seed node. /// For better memory management the returned list should be pooled, see Pathfinding.Util.ListPool. /// </summary> /// <param name="seed">The node to start the search from.</param> /// <param name="tagMask">Optional mask for tags. This is a bitmask.</param> /// <param name="filter">Optional filter for which nodes to search. You can combine this with tagMask = -1 to make the filter determine everything. /// Only walkable nodes are searched regardless of the filter. If the filter function returns false the node will be treated as unwalkable.</param> public static List <GraphNode> GetReachableNodes(GraphNode seed, int tagMask = -1, System.Func <GraphNode, bool> filter = null) { var dfsStack = StackPool <GraphNode> .Claim(); var reachable = ListPool <GraphNode> .Claim(); /// <summary>TODO: Pool</summary> var map = new HashSet <GraphNode>(); System.Action <GraphNode> callback; // Check if we can use the fast path if (tagMask == -1 && filter == null) { callback = (GraphNode node) => { if (node.Walkable && map.Add(node)) { reachable.Add(node); dfsStack.Push(node); } } } ; else { callback = (GraphNode node) => { if (node.Walkable && ((tagMask >> (int)node.Tag) & 0x1) != 0 && map.Add(node)) { if (filter != null && !filter(node)) { return; } reachable.Add(node); dfsStack.Push(node); } } }; callback(seed); while (dfsStack.Count > 0) { dfsStack.Pop().GetConnections(callback); } StackPool <GraphNode> .Release(dfsStack); return(reachable); }
/** Should be called on every node which is updated with this GUO before it is updated. * \param node The node to save fields for. If null, nothing will be done * \see #trackChangedNodes */ public virtual void WillUpdateNode(GraphNode node) { if (trackChangedNodes && node != null) { if (changedNodes == null) { changedNodes = ListPool <GraphNode> .Claim(); backupData = ListPool <ulong> .Claim(); backupPositionData = ListPool <Int3> .Claim(); } changedNodes.Add(node); backupPositionData.Add(node.position); backupData.Add((ulong)node.Penalty << 32 | (ulong)node.Flags); } }
/// <summary> /// Register blocker as being present at the specified node. /// Calling this method multiple times will add multiple instances of the blocker to the node. /// /// Note: The node will not be blocked immediately. Instead the pathfinding /// threads will be paused and then the update will be applied. It is however /// guaranteed to be applied before the next path request is started. /// </summary> public void InternalBlock(GraphNode node, SingleNodeBlocker blocker) { AstarPath.active.AddWorkItem(new AstarWorkItem(() => { List <SingleNodeBlocker> blockersInNode; if (!blocked.TryGetValue(node, out blockersInNode)) { blockersInNode = blocked[node] = ListPool <SingleNodeBlocker> .Claim(); } blockersInNode.Add(blocker); })); }
/** Updates graphs and checks if all nodes are still reachable from each other. * Graphs are updated, then a check is made to see if the nodes are still reachable from each other. * If they are not, the graphs are reverted to before the update and \a false is returned.\n * This is slower than a normal graph update. * All queued graph updates and thread safe callbacks will be flushed during this function. * * \note This might return true for small areas even if there is no possible path if AstarPath.minAreaSize is greater than zero (0). * So when using this, it is recommended to set AstarPath.minAreaSize to 0 (A* Inspector -> Settings -> Pathfinding) * * \param guo The GraphUpdateObject to update the graphs with * \param node1 Node which should have a valid path to \a node2. All nodes should be walkable or \a false will be returned. * \param node2 Node which should have a valid path to \a node1. All nodes should be walkable or \a false will be returned. * \param alwaysRevert If true, reverts the graphs to the old state even if no blocking ocurred */ public static bool UpdateGraphsNoBlock(GraphUpdateObject guo, GraphNode node1, GraphNode node2, bool alwaysRevert = false) { List <GraphNode> buffer = ListPool <GraphNode> .Claim(); buffer.Add(node1); buffer.Add(node2); bool worked = UpdateGraphsNoBlock(guo, buffer, alwaysRevert); ListPool <GraphNode> .Release(buffer); return(worked); }
public static List <NavmeshAdd> GetAllInRange(Bounds b) { List <NavmeshAdd> list = ListPool <NavmeshAdd> .Claim(); for (int i = 0; i < NavmeshAdd.allCuts.Count; i++) { if (NavmeshAdd.allCuts[i].enabled && NavmeshAdd.Intersects(b, NavmeshAdd.allCuts[i].GetBounds())) { list.Add(NavmeshAdd.allCuts[i]); } } return(list); }
public void InternalBlock(GraphNode node, SingleNodeBlocker blocker) { AstarPath.active.AddWorkItem(new AstarWorkItem(delegate { List <SingleNodeBlocker> list; if (!this.blocked.TryGetValue(node, out list)) { List <SingleNodeBlocker> list2 = ListPool <SingleNodeBlocker> .Claim(); this.blocked[node] = list2; list = list2; } list.Add(blocker); }, null)); }
protected override IEnumerable <Progress> ScanInternal() { cachedSourceMeshBoundsMin = sourceMesh != null ? sourceMesh.bounds.min : Vector3.zero; transform = CalculateTransform(); tileZCount = tileXCount = 1; tiles = new NavmeshTile[tileZCount * tileXCount]; TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(this), this); if (sourceMesh == null) { FillWithEmptyTiles(); yield break; } yield return(new Progress(0.0f, "Transforming Vertices")); forcedBoundsSize = sourceMesh.bounds.size * scale; Vector3[] vectorVertices = sourceMesh.vertices; var intVertices = ListPool <Int3> .Claim(vectorVertices.Length); var matrix = Matrix4x4.TRS(-sourceMesh.bounds.min * scale, Quaternion.identity, Vector3.one * scale); // Convert the vertices to integer coordinates and also position them in graph space // so that the minimum of the bounding box of the mesh is at the origin // (the vertices will later be transformed to world space) for (int i = 0; i < vectorVertices.Length; i++) { intVertices.Add((Int3)matrix.MultiplyPoint3x4(vectorVertices[i])); } yield return(new Progress(0.1f, "Compressing Vertices")); // Remove duplicate vertices Int3[] compressedVertices = null; int[] compressedTriangles = null; Polygon.CompressMesh(intVertices, new List <int>(sourceMesh.triangles), out compressedVertices, out compressedTriangles); ListPool <Int3> .Release(ref intVertices); yield return(new Progress(0.2f, "Building Nodes")); ReplaceTile(0, 0, compressedVertices, compressedTriangles); // Signal that tiles have been recalculated to the navmesh cutting system. navmeshUpdateData.OnRecalculatedTiles(tiles); if (OnRecalculatedTiles != null) { OnRecalculatedTiles(tiles.Clone() as NavmeshTile[]); } }
/** Returns all nodes reachable from the seed node. * This function performs a BFS (breadth-first-search) or flood fill of the graph and returns all nodes which can be reached from * the seed node. In almost all cases this will be identical to returning all nodes which have the same area as the seed node. * In the editor areas are displayed as different colors of the nodes. * The only case where it will not be so is when there is a one way path from some part of the area to the seed node * but no path from the seed node to that part of the graph. * * The returned list is sorted by node distance from the seed node * i.e distance is measured in the number of nodes the shortest path from \a seed to that node would pass through. * Note that the distance measurement does not take heuristics, penalties or tag penalties. * * Depending on the number of reachable nodes, this function can take quite some time to calculate * so don't use it too often or it might affect the framerate of your game. * * \param seed The node to start the search from * \param tagMask Optional mask for tags. This is a bitmask. * * \returns A List<Node> containing all nodes reachable from the seed node. * For better memory management the returned list should be pooled, see Pathfinding.Util.ListPool */ public static List <GraphNode> GetReachableNodes(GraphNode seed, int tagMask = -1) { #if ASTAR_PROFILE System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); #endif Stack <GraphNode> stack = StackPool <GraphNode> .Claim(); List <GraphNode> list = ListPool <GraphNode> .Claim(); /** \todo Pool */ var map = new HashSet <GraphNode>(); GraphNodeDelegate callback; if (tagMask == -1) { callback = delegate(GraphNode node) { if (node.Walkable && map.Add(node)) { list.Add(node); stack.Push(node); } }; } else { callback = delegate(GraphNode node) { if (node.Walkable && ((tagMask >> (int)node.Tag) & 0x1) != 0 && map.Add(node)) { list.Add(node); stack.Push(node); } }; } callback(seed); while (stack.Count > 0) { stack.Pop().GetConnections(callback); } StackPool <GraphNode> .Release(stack); #if ASTAR_PROFILE watch.Stop(); Debug.Log((1000 * watch.Elapsed.TotalSeconds).ToString("0.0 ms")); #endif return(list); }
public override void OnDrawGizmosSelected() { base.OnDrawGizmosSelected(); List <Vector3> list = ListPool <Vector3> .Claim(); Vector3 zero = Vector3.zero; this.CalculateOffsets(list, out zero); Gizmos.color = Color.blue; for (int i = 0; i < list.Count - 1; i++) { Gizmos.DrawLine(list[i], list[i + 1]); } }
public override void OnDrawGizmosSelected() { base.OnDrawGizmosSelected(); var buffer = ListPool <Vector3> .Claim(); var endPosition = Vector3.zero; CalculateOffsets(buffer, out endPosition); Gizmos.color = Color.blue; for (var i = 0; i < buffer.Count - 1; i++) { Gizmos.DrawLine(buffer[i], buffer[i + 1]); } }
public static FunnelPortals ConstructFunnelPortals(List <GraphNode> nodes, PathPart part) { if (nodes == null || nodes.Count == 0) { return new FunnelPortals { left = ListPool <Vector3> .Claim(0), right = ListPool <Vector3> .Claim(0) } } ; if (part.endIndex < part.startIndex || part.startIndex < 0 || part.endIndex > nodes.Count) { throw new System.ArgumentOutOfRangeException(); } // Claim temporary lists and try to find lists with a high capacity var left = ListPool <Vector3> .Claim(nodes.Count + 1); var right = ListPool <Vector3> .Claim(nodes.Count + 1); // Add start point left.Add(part.startPoint); right.Add(part.startPoint); // Loop through all nodes in the path (except the last one) for (var i = part.startIndex; i < part.endIndex; i++) { // Get the portal between path[i] and path[i+1] and add it to the left and right lists var portalWasAdded = nodes[i].GetPortal(nodes[i + 1], left, right, false); if (!portalWasAdded) { // Fallback, just use the positions of the nodes left.Add((Vector3)nodes[i].position); right.Add((Vector3)nodes[i].position); left.Add((Vector3)nodes[i + 1].position); right.Add((Vector3)nodes[i + 1].position); } } // Add end point left.Add(part.endPoint); right.Add(part.endPoint); return(new FunnelPortals { left = left, right = right }); }
// Token: 0x0600229B RID: 8859 RVA: 0x00190E64 File Offset: 0x0018F064 public static void GetContours(INavmesh navmesh, Action <List <Int3>, bool> results) { bool[] uses = new bool[3]; Dictionary <int, int> outline = new Dictionary <int, int>(); Dictionary <int, Int3> vertexPositions = new Dictionary <int, Int3>(); HashSet <int> hasInEdge = new HashSet <int>(); navmesh.GetNodes(delegate(GraphNode _node) { TriangleMeshNode triangleMeshNode = _node as TriangleMeshNode; uses[0] = (uses[1] = (uses[2] = false)); if (triangleMeshNode != null) { for (int i = 0; i < triangleMeshNode.connections.Length; i++) { TriangleMeshNode triangleMeshNode2 = triangleMeshNode.connections[i].node as TriangleMeshNode; if (triangleMeshNode2 != null) { int num = triangleMeshNode.SharedEdge(triangleMeshNode2); if (num != -1) { uses[num] = true; } } } for (int j = 0; j < 3; j++) { if (!uses[j]) { int i2 = j; int i3 = (j + 1) % triangleMeshNode.GetVertexCount(); outline[triangleMeshNode.GetVertexIndex(i2)] = triangleMeshNode.GetVertexIndex(i3); hasInEdge.Add(triangleMeshNode.GetVertexIndex(i3)); vertexPositions[triangleMeshNode.GetVertexIndex(i2)] = triangleMeshNode.GetVertex(i2); vertexPositions[triangleMeshNode.GetVertexIndex(i3)] = triangleMeshNode.GetVertex(i3); } } } }); Polygon.TraceContours(outline, hasInEdge, delegate(List <int> chain, bool cycle) { List <Int3> list = ListPool <Int3> .Claim(); for (int i = 0; i < chain.Count; i++) { list.Add(vertexPositions[chain[i]]); } results(list, cycle); }); }
public static Vector3[] ConvexHullXZ(Vector3[] points) { if (points.Length == 0) { return(new Vector3[0]); } List <Vector3> list = ListPool <Vector3> .Claim(); int num = 0; for (int i = 1; i < points.Length; i++) { if (points[i].x < points[num].x) { num = i; } } int num2 = num; int num3 = 0; for (;;) { list.Add(points[num]); int num4 = 0; for (int j = 0; j < points.Length; j++) { if (num4 == num || !VectorMath.RightOrColinearXZ(points[num], points[num4], points[j])) { num4 = j; } } num = num4; num3++; if (num3 > 10000) { break; } if (num == num2) { goto IL_E3; } } Debug.LogWarning("Infinite Loop in Convex Hull Calculation"); IL_E3: Vector3[] result = list.ToArray(); ListPool <Vector3> .Release(list); return(result); }
public virtual void Reset() { if (object.ReferenceEquals(AstarPath.active, null)) { Debug.LogError("No AstarPath object found in the scene. Make sure there is one or do not create paths in Awake"); } this.hasBeenReset = true; this.state = PathState.Created; this.releasedNotSilent = false; this.pathHandler = null; this.callback = null; this._errorLog = string.Empty; this.pathCompleteState = PathCompleteState.NotCalculated; this.path = ListPool <GraphNode> .Claim(64); this.vectorPath = ListPool <VInt3> .Claim(64); this.currentR = null; this.duration = 0f; this.searchIterations = 0; this.searchedNodes = 0; this.nnConstraint = PathNNConstraint.Default; this.next = null; this.radius = 0; this.walkabilityMask = -1; this.height = 0; this.turnRadius = 0; this.speed = 0; this.pathID = 0; this.enabledTags = -1; this.tagPenalties = null; this.callTime = DateTime.get_UtcNow(); AstarPath active = AstarPath.active; if (active != null) { this.pathID = AstarPath.active.GetNextPathID(); this.heuristic = AstarPath.active.heuristic; this.heuristicScale = AstarPath.active.heuristicScale; } else { this.heuristic = Heuristic.Manhattan; this.heuristicScale = 1f; } this.hTarget = VInt3.zero; this.hTargetNode = null; }
public override IEnumerable <Progress> ScanInternal() { transform = CalculateTransform(); tileZCount = tileXCount = 1; tiles = new NavmeshTile[tileZCount * tileXCount]; TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(this), this); if (sourceMesh == null) { FillWithEmptyTiles(); yield break; } yield return(new Progress(0.0f, "Transforming Vertices")); forcedBoundsSize = sourceMesh.bounds.size * scale; Vector3[] vectorVertices = sourceMesh.vertices; var intVertices = ListPool <Int3> .Claim(vectorVertices.Length); var matrix = Matrix4x4.TRS(-sourceMesh.bounds.min * scale, Quaternion.identity, Vector3.one * scale); // Convert the vertices to integer coordinates and also position them in graph space // so that the minimum of the bounding box of the mesh is at the origin // (the vertices will later be transformed to world space) for (int i = 0; i < vectorVertices.Length; i++) { intVertices.Add((Int3)matrix.MultiplyPoint3x4(vectorVertices[i])); } yield return(new Progress(0.1f, "Compressing Vertices")); // Remove duplicate vertices Int3[] compressedVertices = null; int[] compressedTriangles = null; Polygon.CompressMesh(intVertices, new List <int>(sourceMesh.triangles), out compressedVertices, out compressedTriangles); ListPool <Int3> .Release(intVertices); yield return(new Progress(0.2f, "Building Nodes")); ReplaceTile(0, 0, compressedVertices, compressedTriangles); // This may be used by the TileHandlerHelper script to update the tiles // while taking NavmeshCuts into account after the graph has been completely recalculated. if (OnRecalculatedTiles != null) { OnRecalculatedTiles(tiles.Clone() as NavmeshTile[]); } }
// Token: 0x06002648 RID: 9800 RVA: 0x001A5D98 File Offset: 0x001A3F98 public override void Apply(Path p) { if (p.path == null || p.path.Count == 0 || p.vectorPath == null || p.vectorPath.Count == 0) { return; } List <Vector3> list = ListPool <Vector3> .Claim(); List <Funnel.PathPart> list2 = Funnel.SplitIntoParts(p); if (list2.Count == 0) { return; } for (int i = 0; i < list2.Count; i++) { Funnel.PathPart pathPart = list2[i]; if (!pathPart.isLink) { Funnel.FunnelPortals funnel = Funnel.ConstructFunnelPortals(p.path, pathPart); List <Vector3> collection = Funnel.Calculate(funnel, this.unwrap, this.splitAtEveryPortal); list.AddRange(collection); ListPool <Vector3> .Release(ref funnel.left); ListPool <Vector3> .Release(ref funnel.right); ListPool <Vector3> .Release(ref collection); } else { if (i == 0 || list2[i - 1].isLink) { list.Add(pathPart.startPoint); } if (i == list2.Count - 1 || list2[i + 1].isLink) { list.Add(pathPart.endPoint); } } } ListPool <Funnel.PathPart> .Release(ref list2); ListPool <Vector3> .Release(ref p.vectorPath); p.vectorPath = list; }
/** Displays a LayerMask field. * \param label Label to display * \param selected Current LayerMask */ public static LayerMask LayerMaskField(string label, LayerMask selected) { if (Event.current.type == EventType.Layout && System.DateTime.UtcNow.Ticks - lastUpdateTick > 10000000L) { layerNames.Clear(); lastUpdateTick = System.DateTime.UtcNow.Ticks; } string[] currentLayerNames; if (!layerNames.TryGetValue(selected.value, out currentLayerNames)) { var layers = ListPool <string> .Claim(); int emptyLayers = 0; for (int i = 0; i < 32; i++) { string layerName = LayerMask.LayerToName(i); if (layerName != "") { for (; emptyLayers > 0; emptyLayers--) { layers.Add("Layer " + (i - emptyLayers)); } layers.Add(layerName); } else { emptyLayers++; if (((selected.value >> i) & 1) != 0 && selected.value != -1) { for (; emptyLayers > 0; emptyLayers--) { layers.Add("Layer " + (i + 1 - emptyLayers)); } } } } currentLayerNames = layerNames[selected.value] = layers.ToArray(); ListPool <string> .Release(ref layers); } selected.value = EditorGUILayout.MaskField(label, selected.value, currentLayerNames); return(selected); }
/** Convenience method to get a list of all segments of the contours of a graph. * \returns A list of segments. Every 2 elements form a line segment. The first segment is (result[0], result[1]), the second one is (result[2], result[3]) etc. * The line segments are oriented so that the navmesh is on the right side of the segments when seen from above. * * This method works for navmesh, recast, grid graphs and layered grid graphs. For other graph types it will return an empty list. * * If you need more information about how the contours are connected you can take a look at the other variants of this method. * * \snippet MiscSnippets.cs GraphUtilities.GetContours2 * * \shadowimage{navmesh_contour.png} * \shadowimage{grid_contour.png} */ public static List <Vector3> GetContours(NavGraph graph) { List <Vector3> result = ListPool <Vector3> .Claim(); if (graph is INavmesh) { GetContours(graph as INavmesh, (vertices, cycle) => { for (int j = cycle? vertices.Count - 1 : 0, i = 0; i < vertices.Count; j = i, i++) { result.Add((Vector3)vertices[j]); result.Add((Vector3)vertices[i]); } }); } return(result); }
/** Should be called on every node which is updated with this GUO before it is updated. * \param node The node to save fields for. If null, nothing will be done * \see #trackChangedNodes */ public virtual void WillUpdateNode(GraphNode node) { if (trackChangedNodes && node != null) { if (changedNodes == null) { changedNodes = ListPool <GraphNode> .Claim(); backupData = ListPool <uint> .Claim(); backupPositionData = ListPool <Int3> .Claim(); } changedNodes.Add(node); backupPositionData.Add(node.position); backupData.Add(node.Penalty); backupData.Add(node.Flags); #if !ASTAR_NO_GRID_GRAPH // var gg = node as GridNode; // if (gg != null) backupData.Add(gg.InternalGridFlags); #endif } }
public virtual void WillUpdateNode(GraphNode node) { if (this.trackChangedNodes && node != null) { if (this.changedNodes == null) { this.changedNodes = ListPool <GraphNode> .Claim(); this.backupData = ListPool <uint> .Claim(); this.backupPositionData = ListPool <VInt3> .Claim(); } this.changedNodes.Add(node); this.backupPositionData.Add(node.position); this.backupData.Add(node.Penalty); this.backupData.Add(node.Flags); } }
// Token: 0x0600279F RID: 10143 RVA: 0x001B30BC File Offset: 0x001B12BC public static List <GraphNode> GetReachableNodes(GraphNode seed, int tagMask = -1, Func <GraphNode, bool> filter = null) { Stack <GraphNode> dfsStack = StackPool <GraphNode> .Claim(); List <GraphNode> reachable = ListPool <GraphNode> .Claim(); HashSet <GraphNode> map = new HashSet <GraphNode>(); Action <GraphNode> action; if (tagMask == -1 && filter == null) { action = delegate(GraphNode node) { if (node.Walkable && map.Add(node)) { reachable.Add(node); dfsStack.Push(node); } }; } else { action = delegate(GraphNode node) { if (node.Walkable && (tagMask >> (int)node.Tag & 1) != 0 && map.Add(node)) { if (filter != null && !filter(node)) { return; } reachable.Add(node); dfsStack.Push(node); } }; } action(seed); while (dfsStack.Count > 0) { dfsStack.Pop().GetConnections(action); } StackPool <GraphNode> .Release(dfsStack); return(reachable); }
public static Vector3[] ConvexHullXZ(Vector3[] points) { if (points.Length == 0) { return(new Vector3[0]); } List <Vector3> list = ListPool <Vector3> .Claim(); int index = 0; for (int i = 1; i < points.Length; i++) { if (points[i].x < points[index].x) { index = i; } } int num3 = index; int num4 = 0; do { list.Add(points[index]); int num5 = 0; for (int j = 0; j < points.Length; j++) { if ((num5 == index) || !VectorMath.RightOrColinearXZ(points[index], points[num5], points[j])) { num5 = j; } } index = num5; num4++; if (num4 > 0x2710) { Debug.LogWarning("Infinite Loop in Convex Hull Calculation"); break; } }while (index != num3); Vector3[] vectorArray = list.ToArray(); ListPool <Vector3> .Release(list); return(vectorArray); }
public List <Vector3> CurvedNonuniform(List <Vector3> path) { if (this.maxSegmentLength <= 0f) { Debug.LogWarning("Max Segment Length is <= 0 which would cause DivByZero-exception or other nasty errors (avoid this)"); return(path); } int capacity = 0; for (int i = 0; i < (path.Count - 1); i++) { Vector3 vector8 = path[i] - path[i + 1]; float magnitude = vector8.magnitude; for (float k = 0f; k <= magnitude; k += this.maxSegmentLength) { capacity++; } } List <Vector3> list = ListPool <Vector3> .Claim(capacity); Vector3 vector9 = path[1] - path[0]; Vector3 normalized = vector9.normalized; for (int j = 0; j < (path.Count - 1); j++) { Vector3 vector10 = path[j] - path[j + 1]; float num6 = vector10.magnitude; Vector3 vector2 = normalized; Vector3 vector3 = (j >= (path.Count - 2)) ? (path[j + 1] - path[j]).normalized : ((path[j + 2] - path[j + 1]).normalized - (path[j] - path[j + 1]).normalized).normalized; Vector3 vector4 = (Vector3)((vector2 * num6) * this.factor); Vector3 vector5 = (Vector3)((vector3 * num6) * this.factor); Vector3 a = path[j]; Vector3 b = path[j + 1]; float num7 = 1f / num6; for (float m = 0f; m <= num6; m += this.maxSegmentLength) { float t = m * num7; list.Add(GetPointOnCubic(a, b, vector4, vector5, t)); } normalized = vector3; } list[list.Count - 1] = path[path.Count - 1]; return(list); }
/** Returns all nodes reachable from the seed node. * This function performs a BFS (breadth-first-search) or flood fill of the graph and returns all nodes which can be reached from * the seed node. In almost all cases this will be identical to returning all nodes which have the same area as the seed node. * In the editor areas are displayed as different colors of the nodes. * The only case where it will not be so is when there is a one way path from some part of the area to the seed node * but no path from the seed node to that part of the graph. * * The returned list is sorted by node distance from the seed node * i.e distance is measured in the number of nodes the shortest path from \a seed to that node would pass through. * Note that the distance measurement does not take heuristics, penalties or tag penalties. * * Depending on the number of reachable nodes, this function can take quite some time to calculate * so don't use it too often or it might affect the framerate of your game. * * \param seed The node to start the search from * \param tagMask Optional mask for tags. This is a bitmask. * * \returns A List<Node> containing all nodes reachable from the seed node. * For better memory management the returned list should be pooled, see Pathfinding.Util.ListPool */ public static List <GraphNode> GetReachableNodes(GraphNode seed, int tagMask = -1) { Stack <GraphNode> stack = StackPool <GraphNode> .Claim(); List <GraphNode> list = ListPool <GraphNode> .Claim(); /** \todo Pool */ var map = new HashSet <GraphNode>(); GraphNodeDelegate callback; if (tagMask == -1) { callback = delegate(GraphNode node) { if (node.Walkable && map.Add(node)) { list.Add(node); stack.Push(node); } }; } else { callback = delegate(GraphNode node) { if (node.Walkable && ((tagMask >> (int)node.Tag) & 0x1) != 0 && map.Add(node)) { list.Add(node); stack.Push(node); } }; } callback(seed); while (stack.Count > 0) { stack.Pop().GetConnections(callback); } StackPool <GraphNode> .Release(stack); return(list); }
/** Returns points in a spiral centered around the origin with a minimum clearance from other points. * The points are laid out on the involute of a circle * \see http://en.wikipedia.org/wiki/Involute * Which has some nice properties. * All points are separated by \a clearance world units. * This method is O(n), yes if you read the code you will see a binary search, but that binary search * has an upper bound on the number of steps, so it does not yield a log factor. * * \note Consider recycling the list after usage to reduce allocations. * \see Pathfinding.Util.ListPool */ public static List <Vector3> GetSpiralPoints(int count, float clearance) { List <Vector3> pts = ListPool <Vector3> .Claim(count); // The radius of the smaller circle used for generating the involute of a circle // Calculated from the separation distance between the turns float a = clearance / (2 * Mathf.PI); float t = 0; pts.Add(InvoluteOfCircle(a, t)); for (int i = 0; i < count; i++) { Vector3 prev = pts[pts.Count - 1]; // d = -t0/2 + sqrt( t0^2/4 + 2d/a ) // Minimum angle (radians) which would create an arc distance greater than clearance float d = -t / 2 + Mathf.Sqrt(t * t / 4 + 2 * clearance / a); // Binary search for separating this point and the previous one float mn = t + d; float mx = t + 2 * d; while (mx - mn > 0.01f) { float mid = (mn + mx) / 2; Vector3 p = InvoluteOfCircle(a, mid); if ((p - prev).sqrMagnitude < clearance * clearance) { mn = mid; } else { mx = mid; } } pts.Add(InvoluteOfCircle(a, mx)); t = mx; } return(pts); }