/** Add a node with the specified type to the graph at the specified position. * * \param node This must be a node created using T(AstarPath.active) right before the call to this method. * The node parameter is only there because there is no new(AstarPath) constraint on * generic type parameters. * \param position The node will be set to this position. * \note Vector3 can be casted to Int3 using (Int3)myVector. * * \note This needs to be called when it is safe to update nodes, which is * - when scanning * - during a graph update * - inside a callback registered using AstarPath.RegisterSafeUpdate * * \see AstarPath.RegisterSafeUpdate */ public T AddNode <T>(T node, Int3 position) where T : PointNode { if (nodes == null || nodeCount == nodes.Length) { var newNodes = new PointNode[nodes != null ? System.Math.Max(nodes.Length + 4, nodes.Length * 2) : 4]; if (nodes != null) { nodes.CopyTo(newNodes, 0); } nodes = newNodes; } node.SetPosition(position); node.GraphIndex = graphIndex; node.Walkable = true; nodes[nodeCount] = node; nodeCount++; AddToLookup(node); return(node); }
public override void DeserializeExtraInfo(GraphSerializationContext ctx) { int count = ctx.reader.ReadInt32(); if (count == -1) { nodes = null; return; } nodes = new PointNode[count]; nodeCount = count; for (int i = 0; i < nodes.Length; i++) { if (ctx.reader.ReadInt32() == -1) { continue; } nodes[i] = new PointNode(active); nodes[i].DeserializeNode(ctx); } }
/** Add a node with the specified type to the graph at the specified position. * * \param node This must be a node created using T(AstarPath.active) right before the call to this method. * The node parameter is only there because there is no new(AstarPath) constraint on * generic type parameters. * \param position The node will be set to this position. * \note Vector3 can be casted to Int3 using (Int3)myVector. * * \note This needs to be called when it is safe to update nodes, which is * - when scanning * - during a graph update * - inside a callback registered using AstarPath.RegisterSafeUpdate * * \see AstarPath.RegisterSafeUpdate */ public T AddNode <T>(T node, Int3 position) where T : PointNode { if (nodes == null || nodeCount == nodes.Length) { var nds = new PointNode[nodes != null ? System.Math.Max(nodes.Length + 4, nodes.Length * 2) : 4]; for (int i = 0; i < nodeCount; i++) { nds[i] = nodes[i]; } nodes = nds; } node.SetPosition(position); node.GraphIndex = graphIndex; node.Walkable = true; nodes[nodeCount] = node; nodeCount++; AddToLookup(node); return(node); }
/** Add a node with the specified type to the graph at the specified position. * \note Vector3 can be casted to Int3 using (Int3)myVector. * * \param nd This must be a node created using T(AstarPath.active) right before the call to this method. * The node parameter is only there because there is no new(AstarPath) constraint on * generic type parameters. */ public T AddNode <T> (T nd, Int3 position) where T : PointNode { if (nodes == null || nodeCount == nodes.Length) { var nds = new PointNode[nodes != null ? Math.Max(nodes.Length + 4, nodes.Length * 2) : 4]; for (var i = 0; i < nodeCount; i++) { nds[i] = nodes[i]; } nodes = nds; } //T nd = new T( active );//new PointNode ( active ); nd.SetPosition(position); nd.GraphIndex = graphIndex; nd.Walkable = true; nodes[nodeCount] = nd; nodeCount++; AddToLookup(nd); return(nd); }
public void InternalOnPostScan() { if (this.EndTransform == null || this.StartTransform == null) { return; } if (AstarPath.active.astarData.pointGraph == null) { AstarPath.active.astarData.AddGraph(new PointGraph()); } NodeLink2 x; if (this.startNode != null && NodeLink2.reference.TryGetValue(this.startNode, out x) && x == this) { NodeLink2.reference.Remove(this.startNode); } NodeLink2 x2; if (this.endNode != null && NodeLink2.reference.TryGetValue(this.endNode, out x2) && x2 == this) { NodeLink2.reference.Remove(this.endNode); } this.startNode = AstarPath.active.astarData.pointGraph.AddNode((Int3)this.StartTransform.position); this.endNode = AstarPath.active.astarData.pointGraph.AddNode((Int3)this.EndTransform.position); this.connectedNode1 = null; this.connectedNode2 = null; if (this.startNode == null || this.endNode == null) { this.startNode = null; this.endNode = null; return; } this.postScanCalled = true; NodeLink2.reference[this.startNode] = this; NodeLink2.reference[this.endNode] = this; this.Apply(true); }
// Token: 0x060025B4 RID: 9652 RVA: 0x001A1470 File Offset: 0x0019F670 private NNInfoInternal GetNearestInternal(Vector3 position, NNConstraint constraint, bool fastCheck) { if (this.nodes == null) { return(default(NNInfoInternal)); } if (this.optimizeForSparseGraph) { return(new NNInfoInternal(this.lookupTree.GetNearest((Int3)position, fastCheck ? null : constraint))); } float num = (constraint == null || constraint.constrainDistance) ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity; NNInfoInternal nninfoInternal = new NNInfoInternal(null); float num2 = float.PositiveInfinity; float num3 = float.PositiveInfinity; for (int i = 0; i < this.nodeCount; i++) { PointNode pointNode = this.nodes[i]; float sqrMagnitude = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; nninfoInternal.node = pointNode; } if (sqrMagnitude < num3 && sqrMagnitude < num && (constraint == null || constraint.Suitable(pointNode))) { num3 = sqrMagnitude; nninfoInternal.constrainedNode = pointNode; } } if (!fastCheck) { nninfoInternal.node = nninfoInternal.constrainedNode; } nninfoInternal.UpdateInfo(); return(nninfoInternal); }
// Token: 0x060025B6 RID: 9654 RVA: 0x001A1584 File Offset: 0x0019F784 public T AddNode <T>(T node, Int3 position) where T : PointNode { if (this.nodes == null || this.nodeCount == this.nodes.Length) { PointNode[] array = new PointNode[(this.nodes != null) ? Math.Max(this.nodes.Length + 4, this.nodes.Length * 2) : 4]; if (this.nodes != null) { this.nodes.CopyTo(array, 0); } this.nodes = array; } node.SetPosition(position); node.GraphIndex = this.graphIndex; node.Walkable = true; this.nodes[this.nodeCount] = node; int nodeCount = this.nodeCount; this.nodeCount = nodeCount + 1; if (this.optimizeForSparseGraph) { this.AddToLookup(node); } return(node); }
/** Rebuilds the lookup structure for nodes. * * This is used when #optimizeForSparseGraph is enabled. * * You should call this method every time you move a node in the graph manually and * you are using #optimizeForSparseGraph, otherwise pathfinding might not work correctly. * * \astarpro */ public void RebuildNodeLookup() { if (!optimizeForSparseGraph) { return; } if (maxDistance == 0) { lookupCellSize = (Int3)limits; } else { lookupCellSize.x = Mathf.CeilToInt(Int3.Precision * (limits.x != 0 ? Mathf.Min(maxDistance, limits.x) : maxDistance)); lookupCellSize.y = Mathf.CeilToInt(Int3.Precision * (limits.y != 0 ? Mathf.Min(maxDistance, limits.y) : maxDistance)); lookupCellSize.z = Mathf.CeilToInt(Int3.Precision * (limits.z != 0 ? Mathf.Min(maxDistance, limits.z) : maxDistance)); } if (optimizeFor2D) { lookupCellSize.y = 0; } if (nodeLookup == null) { nodeLookup = new Dictionary <Int3, PointNode>(); } nodeLookup.Clear(); for (int i = 0; i < nodeCount; i++) { PointNode node = nodes[i]; AddToLookup(node); } }
/// <summary> /// Updates an area in the list graph. /// Recalculates possibly affected connections, i.e all connectionlines passing trough the bounds of the guo will be recalculated /// </summary> void IUpdatableGraph.UpdateArea(GraphUpdateObject guo) { if (nodes == null) { return; } for (int i = 0; i < nodeCount; i++) { var node = nodes[i]; if (guo.bounds.Contains((Vector3)node.position)) { guo.WillUpdateNode(node); guo.Apply(node); } } if (guo.updatePhysics) { // Use a copy of the bounding box, we should not change the GUO's bounding box since it might be used for other graph updates Bounds bounds = guo.bounds; if (thickRaycast) { // Expand the bounding box to account for the thick raycast bounds.Expand(thickRaycastRadius * 2); } // Create a temporary list used for holding connection data List <Connection> tmpList = Pathfinding.Util.ListPool <Connection> .Claim(); for (int i = 0; i < nodeCount; i++) { PointNode node = nodes[i]; var nodePos = (Vector3)node.position; List <Connection> conn = null; for (int j = 0; j < nodeCount; j++) { if (j == i) { continue; } var otherNodePos = (Vector3)nodes[j].position; // Check if this connection intersects the bounding box. // If it does we need to recalculate that connection. if (VectorMath.SegmentIntersectsBounds(bounds, nodePos, otherNodePos)) { float dist; PointNode other = nodes[j]; bool contains = node.ContainsConnection(other); bool validConnection = IsValidConnection(node, other, out dist); // Fill the 'conn' list when we need to change a connection if (conn == null && (contains != validConnection)) { tmpList.Clear(); conn = tmpList; conn.AddRange(node.connections); } if (!contains && validConnection) { // A new connection should be added uint cost = (uint)Mathf.RoundToInt(dist * Int3.FloatPrecision); conn.Add(new Connection(other, cost)); RegisterConnectionLength((other.position - node.position).sqrMagnitudeLong); } else if (contains && !validConnection) { // A connection should be removed for (int q = 0; q < conn.Count; q++) { if (conn[q].node == other) { conn.RemoveAt(q); break; } } } } } // Save the new connections if any were changed if (conn != null) { node.connections = conn.ToArray(); node.SetConnectivityDirty(); } } // Release buffers back to the pool Pathfinding.Util.ListPool <Connection> .Release(ref tmpList); } }
void AddToLookup(PointNode node) { lookupTree.Add(node); }
/** Updates an area in the list graph. * Recalculates possibly affected connections, i.e all connectionlines passing trough the bounds of the \a guo will be recalculated * \astarpro */ public void UpdateArea(GraphUpdateObject guo) { if (nodes == null) { return; } for (int i = 0; i < nodeCount; i++) { if (guo.bounds.Contains((Vector3)nodes[i].position)) { guo.WillUpdateNode(nodes[i]); guo.Apply(nodes[i]); } } if (guo.updatePhysics) { //Use a copy of the bounding box, we should not change the GUO's bounding box since it might be used for other graph updates Bounds bounds = guo.bounds; if (thickRaycast) { //Expand the bounding box to account for the thick raycast bounds.Expand(thickRaycastRadius * 2); } //Create two temporary arrays used for holding new connections and costs List <GraphNode> tmp_arr = Pathfinding.Util.ListPool <GraphNode> .Claim(); List <uint> tmp_arr2 = Pathfinding.Util.ListPool <uint> .Claim(); for (int i = 0; i < nodeCount; i++) { PointNode node = nodes[i]; var a = (Vector3)node.position; List <GraphNode> conn = null; List <uint> costs = null; for (int j = 0; j < nodeCount; j++) { if (j == i) { continue; } var b = (Vector3)nodes[j].position; if (VectorMath.SegmentIntersectsBounds(bounds, a, b)) { float dist; PointNode other = nodes[j]; bool contains = node.ContainsConnection(other); bool validConnection = IsValidConnection(node, other, out dist); if (!contains && validConnection) { // A new connection should be added if (conn == null) { tmp_arr.Clear(); tmp_arr2.Clear(); conn = tmp_arr; costs = tmp_arr2; conn.AddRange(node.connections); costs.AddRange(node.connectionCosts); } uint cost = (uint)Mathf.RoundToInt(dist * Int3.FloatPrecision); conn.Add(other); costs.Add(cost); } else if (contains && !validConnection) { // A connection should be removed if (conn == null) { tmp_arr.Clear(); tmp_arr2.Clear(); conn = tmp_arr; costs = tmp_arr2; conn.AddRange(node.connections); costs.AddRange(node.connectionCosts); } int p = conn.IndexOf(other); //Shouldn't have to check for it, but who knows what might go wrong if (p != -1) { conn.RemoveAt(p); costs.RemoveAt(p); } } } } // Save the new connections if any were changed if (conn != null) { node.connections = conn.ToArray(); node.connectionCosts = costs.ToArray(); } } // Release buffers back to the pool Pathfinding.Util.ListPool <GraphNode> .Release(tmp_arr); Pathfinding.Util.ListPool <uint> .Release(tmp_arr2); } }
public override void ScanInternal(OnScanStatus statusCallback) { if (root == null) { //If there is no root object, try to find nodes with the specified tag instead GameObject[] gos = searchTag != null?GameObject.FindGameObjectsWithTag(searchTag) : null; if (gos == null) { nodes = new PointNode[0]; nodeCount = 0; return; } //Create and set up the found nodes nodes = new PointNode[gos.Length]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } for (int i = 0; i < gos.Length; i++) { nodes[i].SetPosition((Int3)gos[i].transform.position); nodes[i].Walkable = true; nodes[i].gameObject = gos[i].gameObject; } } else { //Search the root for children and create nodes for them if (!recursive) { nodes = new PointNode[root.childCount]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } int c = 0; foreach (Transform child in root) { nodes[c].SetPosition((Int3)child.position); nodes[c].Walkable = true; nodes[c].gameObject = child.gameObject; c++; } } else { nodes = new PointNode[CountChildren(root)]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } //CreateNodes (CountChildren (root)); int startID = 0; AddChildren(ref startID, root); } } if (maxDistance >= 0) { //To avoid too many allocations, these lists are reused for each node var connections = new List <PointNode>(3); var costs = new List <uint>(3); //Loop through all nodes and add connections to other nodes for (int i = 0; i < nodes.Length; i++) { connections.Clear(); costs.Clear(); PointNode node = nodes[i]; // Only brute force is available in the free version for (int j = 0; j < nodes.Length; j++) { if (i == j) { continue; } PointNode other = nodes[j]; float dist; if (IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } } node.connections = connections.ToArray(); node.connectionCosts = costs.ToArray(); } } }
public void InternalOnPostScan () { if ( EndTransform == null || StartTransform == null ) return; #if !ASTAR_NO_POINT_GRAPH if ( AstarPath.active.astarData.pointGraph == null ) { AstarPath.active.astarData.AddGraph ( new PointGraph () ); } #endif if ( startNode != null) { NodeLink2 tmp; if (reference.TryGetValue (startNode, out tmp) && tmp == this) reference.Remove (startNode); } if ( endNode != null) { NodeLink2 tmp; if (reference.TryGetValue (endNode, out tmp) && tmp == this) reference.Remove (endNode); } #if !ASTAR_NO_POINT_GRAPH //Get nearest nodes from the first point graph, assuming both start and end transforms are nodes startNode = AstarPath.active.astarData.pointGraph.AddNode ( (Int3)StartTransform.position );//AstarPath.active.astarData.pointGraph.GetNearest(StartTransform.position).node as PointNode; endNode = AstarPath.active.astarData.pointGraph.AddNode ( (Int3)EndTransform.position ); //AstarPath.active.astarData.pointGraph.GetNearest(EndTransform.position).node as PointNode; #else throw new System.Exception ("Point graph is not included. Check your A* optimization settings."); #endif connectedNode1 = null; connectedNode2 = null; if (startNode == null || endNode == null) { startNode = null; endNode = null; return; } postScanCalled = true; reference[startNode] = this; reference[endNode] = this; Apply( true ); }
// Token: 0x06000526 RID: 1318 RVA: 0x0002CF88 File Offset: 0x0002B388 public override void ScanInternal(OnScanStatus statusCallback) { if (this.root == null) { GameObject[] array = GameObject.FindGameObjectsWithTag(this.searchTag); if (array == null) { this.nodes = new PointNode[0]; this.nodeCount = 0; return; } this.nodes = new PointNode[array.Length]; this.nodeCount = this.nodes.Length; for (int i = 0; i < this.nodes.Length; i++) { this.nodes[i] = new PointNode(this.active); } for (int j = 0; j < array.Length; j++) { this.nodes[j].SetPosition((Int3)array[j].transform.position); this.nodes[j].Walkable = true; this.nodes[j].gameObject = array[j].gameObject; } } else if (!this.recursive) { this.nodes = new PointNode[this.root.childCount]; this.nodeCount = this.nodes.Length; for (int k = 0; k < this.nodes.Length; k++) { this.nodes[k] = new PointNode(this.active); } int num = 0; IEnumerator enumerator = this.root.GetEnumerator(); try { while (enumerator.MoveNext()) { object obj = enumerator.Current; Transform transform = (Transform)obj; this.nodes[num].SetPosition((Int3)transform.position); this.nodes[num].Walkable = true; this.nodes[num].gameObject = transform.gameObject; num++; } } finally { IDisposable disposable; if ((disposable = (enumerator as IDisposable)) != null) { disposable.Dispose(); } } } else { this.nodes = new PointNode[PointGraph.CountChildren(this.root)]; this.nodeCount = this.nodes.Length; for (int l = 0; l < this.nodes.Length; l++) { this.nodes[l] = new PointNode(this.active); } int num2 = 0; this.AddChildren(ref num2, this.root); } if (this.optimizeForSparseGraph) { this.RebuildNodeLookup(); } if (this.maxDistance >= 0f) { List <PointNode> list = new List <PointNode>(3); List <uint> list2 = new List <uint>(3); for (int m = 0; m < this.nodes.Length; m++) { list.Clear(); list2.Clear(); PointNode pointNode = this.nodes[m]; if (this.optimizeForSparseGraph) { Int3 lhs = this.WorldToLookupSpace(pointNode.position); int num3 = (this.lookupCellSize.y != 0) ? PointGraph.ThreeDNeighbours.Length : 9; for (int n = 0; n < num3; n++) { Int3 key = lhs + PointGraph.ThreeDNeighbours[n]; PointNode next; if (this.nodeLookup.TryGetValue(key, out next)) { while (next != null) { float num4 = 0f; if (this.IsValidConnection(pointNode, next, out num4)) { list.Add(next); list2.Add((uint)Mathf.RoundToInt(num4 * 1000f)); } next = next.next; } } } } else { for (int num5 = 0; num5 < this.nodes.Length; num5++) { if (m != num5) { PointNode pointNode2 = this.nodes[num5]; float num6 = 0f; if (this.IsValidConnection(pointNode, pointNode2, out num6)) { list.Add(pointNode2); list2.Add((uint)Mathf.RoundToInt(num6 * 1000f)); } } } } pointNode.connections = list.ToArray(); pointNode.connectionCosts = list2.ToArray(); } } }
private void PopulateNodes(IList<Vector3> waypoints, int tag, bool isWalkable, ref int nextNodeIndex) { int lastNodeIndex = nextNodeIndex + waypoints.Count; for (int index = nextNodeIndex; index < lastNodeIndex; index++) { PointNode node = new PointNode(active); node.SetPosition((Int3)waypoints[index - nextNodeIndex]); node.Walkable = isWalkable; node.Tag = (uint)tag; nodes[index] = node; } nextNodeIndex = lastNodeIndex; }
/** Updates an area in the list graph. * Recalculates possibly affected connections, i.e all connectionlines passing trough the bounds of the \a guo will be recalculated * \astarpro */ public void UpdateArea(GraphUpdateObject guo) { if (nodes == null) { return; } for (int i = 0; i < nodeCount; i++) { if (guo.bounds.Contains((Vector3)nodes[i].position)) { guo.WillUpdateNode(nodes[i]); guo.Apply(nodes[i]); } } if (guo.updatePhysics) { //Use a copy of the bounding box, we should not change the GUO's bounding box since it might be used for other graph updates Bounds bounds = guo.bounds; if (thickRaycast) { //Expand the bounding box to account for the thick raycast bounds.Expand(thickRaycastRadius * 2); } //Create two temporary arrays used for holding new connections and costs List <GraphNode> tmp_arr = Pathfinding.Util.ListPool <GraphNode> .Claim(); List <uint> tmp_arr2 = Pathfinding.Util.ListPool <uint> .Claim(); for (int i = 0; i < nodeCount; i++) { PointNode node = nodes[i] as PointNode; Vector3 a = (Vector3)node.position; List <GraphNode> conn = null; List <uint> costs = null; for (int j = 0; j < nodeCount; j++) { if (j == i) { continue; } Vector3 b = (Vector3)nodes[j].position; if (Polygon.LineIntersectsBounds(bounds, a, b)) { float dist; PointNode other = nodes[j] as PointNode; bool contains = node.ContainsConnection(other); //Note, the IsValidConnection test will actually only be done once //no matter what,so there is no performance penalty there if (!contains && IsValidConnection(node, other, out dist)) { //Debug.DrawLine (a+Vector3.up*0.1F,b+Vector3.up*0.1F,Color.green); if (conn == null) { tmp_arr.Clear(); tmp_arr2.Clear(); conn = tmp_arr; costs = tmp_arr2; conn.AddRange(node.connections); costs.AddRange(node.connectionCosts); } uint cost = (uint)Mathf.RoundToInt(dist * Int3.FloatPrecision); conn.Add(other); costs.Add(cost); } else if (contains && !IsValidConnection(node, other, out dist)) { //Debug.DrawLine (a+Vector3.up*0.5F*Random.value,b+Vector3.up*0.5F*Random.value,Color.red); if (conn == null) { tmp_arr.Clear(); tmp_arr2.Clear(); conn = tmp_arr; costs = tmp_arr2; conn.AddRange(node.connections); costs.AddRange(node.connectionCosts); } int p = conn.IndexOf(other); //Shouldn't have to check for it, but who knows what might go wrong if (p != -1) { conn.RemoveAt(p); costs.RemoveAt(p); } } } } if (conn != null) { node.connections = conn.ToArray(); node.connectionCosts = costs.ToArray(); } } Pathfinding.Util.ListPool <GraphNode> .Release(tmp_arr); Pathfinding.Util.ListPool <uint> .Release(tmp_arr2); } }
public override void ScanInternal(OnScanStatus statusCallback) { if (root == null) { //If there is no root object, try to find nodes with the specified tag instead GameObject[] gos = GameObject.FindGameObjectsWithTag(searchTag); nodeGameObjects = gos; if (gos == null) { nodes = new PointNode[0]; nodeCount = 0; return; } //Create and set up the found nodes nodes = new PointNode[gos.Length]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } //CreateNodes (gos.Length); for (int i = 0; i < gos.Length; i++) { (nodes[i] as PointNode).SetPosition((Int3)gos[i].transform.position); nodes[i].Walkable = true; #if !AstarRelease && FALSE NodeObject nobj = gos[i].GetComponent <NodeObject>(); if (nobj != null) { nodes[i].Walkable = nobj.walkable; } #endif } } else { //Search the root for children and create nodes for them if (!recursive) { nodes = new PointNode[root.childCount]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } nodeGameObjects = new GameObject[nodes.Length]; int c = 0; foreach (Transform child in root) { (nodes[c] as PointNode).SetPosition((Int3)child.position); nodes[c].Walkable = true; nodeGameObjects[c] = child.gameObject; #if !AstarRelease && FALSE NodeObject nobj = child.GetComponent <NodeObject>(); if (nobj != null) { nodes[c].Walkable = nobj.walkable; } #endif c++; } } else { nodes = new PointNode[CountChildren(root)]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } //CreateNodes (CountChildren (root)); nodeGameObjects = new GameObject[nodes.Length]; int startID = 0; AddChildren(ref startID, root); } } if (optimizeForSparseGraph) { RebuildNodeLookup(); } if (maxDistance >= 0) { //To avoid too many allocations, these lists are reused for each node List <PointNode> connections = new List <PointNode>(3); List <uint> costs = new List <uint>(3); //Loop through all nodes and add connections to other nodes for (int i = 0; i < nodes.Length; i++) { connections.Clear(); costs.Clear(); PointNode node = nodes[i]; if (optimizeForSparseGraph) { Int3 p = WorldToLookupSpace(node.position); int l = lookupCellSize.y == 0 ? 9 : ThreeDNeighbours.Length; for (int j = 0; j < l; j++) { Int3 np = p + ThreeDNeighbours[j]; PointNode other; if (nodeLookup.TryGetValue(np, out other)) { while (other != null) { float dist = 0; if (IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } other = other.next; } } } } else { // Only brute force is available in the free version for (int j = 0; j < nodes.Length; j++) { if (i == j) { continue; } PointNode other = nodes[j]; float dist = 0; if (IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } } } node.connections = connections.ToArray(); node.connectionCosts = costs.ToArray(); } } //GC can clear this up now. nodeGameObjects = null; }
public override NNInfoInternal GetNearestForce(Vector3 position, NNConstraint constraint) { if (this.nodes == null) { return(new NNInfoInternal()); } float num = !constraint.constrainDistance ? float.PositiveInfinity : AstarPath.active.maxNearestNodeDistanceSqr; float positiveInfinity = float.PositiveInfinity; GraphNode node = null; float num3 = float.PositiveInfinity; GraphNode node2 = null; if (this.optimizeForSparseGraph) { PointNode next; Int3 key = this.WorldToLookupSpace((Int3)position); Int3 num5 = key - this.minLookup; int num6 = 0; int introduced48 = Math.Max(num6, Math.Abs(num5.x)); int introduced49 = Math.Max(introduced48, Math.Abs(num5.y)); num6 = Math.Max(introduced49, Math.Abs(num5.z)); num5 = key - this.maxLookup; int introduced50 = Math.Max(num6, Math.Abs(num5.x)); int introduced51 = Math.Max(introduced50, Math.Abs(num5.y)); num6 = Math.Max(introduced51, Math.Abs(num5.z)); if (this.nodeLookup.TryGetValue(key, out next)) { while (next != null) { Vector3 vector = position - ((Vector3)next.position); float sqrMagnitude = vector.sqrMagnitude; if (sqrMagnitude < positiveInfinity) { positiveInfinity = sqrMagnitude; node = next; } if ((constraint == null) || (((sqrMagnitude < num3) && (sqrMagnitude < num)) && constraint.Suitable(next))) { num3 = sqrMagnitude; node2 = next; } next = next.next; } } for (int i = 1; i <= num6; i++) { if (i >= 20) { UnityEngine.Debug.LogWarning("Aborting GetNearest call at maximum distance because it has iterated too many times.\nIf you get this regularly, check your settings for PointGraph -> <b>Optimize For Sparse Graph</b> and PointGraph -> <b>Optimize For 2D</b>.\nThis happens when the closest node was very far away (20*link distance between nodes). When optimizing for sparse graphs, getting the nearest node from far away positions is <b>very slow</b>.\n"); break; } if (this.lookupCellSize.y == 0) { Int3 num9 = key + new Int3(-i, 0, -i); for (int j = 0; j <= (2 * i); j++) { if (this.nodeLookup.TryGetValue(num9 + new Int3(j, 0, 0), out next)) { while (next != null) { Vector3 vector2 = position - ((Vector3)next.position); float num11 = vector2.sqrMagnitude; if (num11 < positiveInfinity) { positiveInfinity = num11; node = next; } if ((constraint == null) || (((num11 < num3) && (num11 < num)) && constraint.Suitable(next))) { num3 = num11; node2 = next; } next = next.next; } } if (this.nodeLookup.TryGetValue(num9 + new Int3(j, 0, 2 * i), out next)) { while (next != null) { Vector3 vector3 = position - ((Vector3)next.position); float num12 = vector3.sqrMagnitude; if (num12 < positiveInfinity) { positiveInfinity = num12; node = next; } if ((constraint == null) || (((num12 < num3) && (num12 < num)) && constraint.Suitable(next))) { num3 = num12; node2 = next; } next = next.next; } } } for (int k = 1; k < (2 * i); k++) { if (this.nodeLookup.TryGetValue(num9 + new Int3(0, 0, k), out next)) { while (next != null) { Vector3 vector4 = position - ((Vector3)next.position); float num14 = vector4.sqrMagnitude; if (num14 < positiveInfinity) { positiveInfinity = num14; node = next; } if ((constraint == null) || (((num14 < num3) && (num14 < num)) && constraint.Suitable(next))) { num3 = num14; node2 = next; } next = next.next; } } if (this.nodeLookup.TryGetValue(num9 + new Int3(2 * i, 0, k), out next)) { while (next != null) { Vector3 vector5 = position - ((Vector3)next.position); float num15 = vector5.sqrMagnitude; if (num15 < positiveInfinity) { positiveInfinity = num15; node = next; } if ((constraint == null) || (((num15 < num3) && (num15 < num)) && constraint.Suitable(next))) { num3 = num15; node2 = next; } next = next.next; } } } } else { Int3 num16 = key + new Int3(-i, -i, -i); for (int m = 0; m <= (2 * i); m++) { for (int num18 = 0; num18 <= (2 * i); num18++) { if (this.nodeLookup.TryGetValue(num16 + new Int3(m, num18, 0), out next)) { while (next != null) { Vector3 vector6 = position - ((Vector3)next.position); float num19 = vector6.sqrMagnitude; if (num19 < positiveInfinity) { positiveInfinity = num19; node = next; } if ((constraint == null) || (((num19 < num3) && (num19 < num)) && constraint.Suitable(next))) { num3 = num19; node2 = next; } next = next.next; } } if (this.nodeLookup.TryGetValue(num16 + new Int3(m, num18, 2 * i), out next)) { while (next != null) { Vector3 vector7 = position - ((Vector3)next.position); float num20 = vector7.sqrMagnitude; if (num20 < positiveInfinity) { positiveInfinity = num20; node = next; } if ((constraint == null) || (((num20 < num3) && (num20 < num)) && constraint.Suitable(next))) { num3 = num20; node2 = next; } next = next.next; } } } } for (int n = 1; n < (2 * i); n++) { for (int num22 = 0; num22 <= (2 * i); num22++) { if (this.nodeLookup.TryGetValue(num16 + new Int3(0, num22, n), out next)) { while (next != null) { Vector3 vector8 = position - ((Vector3)next.position); float num23 = vector8.sqrMagnitude; if (num23 < positiveInfinity) { positiveInfinity = num23; node = next; } if ((constraint == null) || (((num23 < num3) && (num23 < num)) && constraint.Suitable(next))) { num3 = num23; node2 = next; } next = next.next; } } if (this.nodeLookup.TryGetValue(num16 + new Int3(2 * i, num22, n), out next)) { while (next != null) { Vector3 vector9 = position - ((Vector3)next.position); float num24 = vector9.sqrMagnitude; if (num24 < positiveInfinity) { positiveInfinity = num24; node = next; } if ((constraint == null) || (((num24 < num3) && (num24 < num)) && constraint.Suitable(next))) { num3 = num24; node2 = next; } next = next.next; } } } } for (int num25 = 1; num25 < (2 * i); num25++) { for (int num26 = 1; num26 < (2 * i); num26++) { if (this.nodeLookup.TryGetValue(num16 + new Int3(num25, 0, num26), out next)) { while (next != null) { Vector3 vector10 = position - ((Vector3)next.position); float num27 = vector10.sqrMagnitude; if (num27 < positiveInfinity) { positiveInfinity = num27; node = next; } if ((constraint == null) || (((num27 < num3) && (num27 < num)) && constraint.Suitable(next))) { num3 = num27; node2 = next; } next = next.next; } } if (this.nodeLookup.TryGetValue(num16 + new Int3(num25, 2 * i, num26), out next)) { while (next != null) { Vector3 vector11 = position - ((Vector3)next.position); float num28 = vector11.sqrMagnitude; if (num28 < positiveInfinity) { positiveInfinity = num28; node = next; } if ((constraint == null) || (((num28 < num3) && (num28 < num)) && constraint.Suitable(next))) { num3 = num28; node2 = next; } next = next.next; } } } } } if (node2 != null) { num6 = Math.Min(num6, i + 1); } } } else { for (int num29 = 0; num29 < this.nodeCount; num29++) { PointNode node4 = this.nodes[num29]; Vector3 vector12 = position - ((Vector3)node4.position); float num30 = vector12.sqrMagnitude; if (num30 < positiveInfinity) { positiveInfinity = num30; node = node4; } if ((constraint == null) || (((num30 < num3) && (num30 < num)) && constraint.Suitable(node4))) { num3 = num30; node2 = node4; } } } NNInfoInternal internal2 = new NNInfoInternal(node); internal2.constrainedNode = node2; if (node2 != null) { internal2.constClampedPosition = (Vector3)node2.position; return(internal2); } if (node != null) { internal2.constrainedNode = node; internal2.constClampedPosition = (Vector3)node.position; } return(internal2); }
public override IEnumerable <Progress> ScanInternal() { yield return(new Progress(0f, "Searching for GameObjects")); if (this.root == null) { GameObject[] gos = (this.searchTag == null) ? null : GameObject.FindGameObjectsWithTag(this.searchTag); if (gos == null) { this.nodes = new PointNode[0]; this.nodeCount = 0; yield break; } yield return(new Progress(0.1f, "Creating nodes")); this.nodes = new PointNode[gos.Length]; this.nodeCount = this.nodes.Length; for (int j = 0; j < this.nodes.Length; j++) { this.nodes[j] = new PointNode(this.active); } for (int k = 0; k < gos.Length; k++) { this.nodes[k].SetPosition((Int3)gos[k].transform.position); this.nodes[k].Walkable = true; this.nodes[k].gameObject = gos[k].gameObject; } } else if (!this.recursive) { this.nodes = new PointNode[this.root.childCount]; this.nodeCount = this.nodes.Length; for (int l = 0; l < this.nodes.Length; l++) { this.nodes[l] = new PointNode(this.active); } int num = 0; IEnumerator enumerator = this.root.GetEnumerator(); try { while (enumerator.MoveNext()) { object obj = enumerator.Current; Transform transform = (Transform)obj; this.nodes[num].SetPosition((Int3)transform.position); this.nodes[num].Walkable = true; this.nodes[num].gameObject = transform.gameObject; num++; } } finally { IDisposable disposable; if ((disposable = (enumerator as IDisposable)) != null) { disposable.Dispose(); } } } else { this.nodes = new PointNode[PointGraph.CountChildren(this.root)]; this.nodeCount = this.nodes.Length; for (int m = 0; m < this.nodes.Length; m++) { this.nodes[m] = new PointNode(this.active); } int num2 = 0; this.AddChildren(ref num2, this.root); } if (this.optimizeForSparseGraph) { yield return(new Progress(0.15f, "Building node lookup")); this.RebuildNodeLookup(); } if (this.maxDistance >= 0f) { List <PointNode> connections = new List <PointNode>(); List <uint> costs = new List <uint>(); List <GraphNode> candidateConnections = new List <GraphNode>(); long maxPossibleSqrRange; if (this.maxDistance == 0f && (this.limits.x == 0f || this.limits.y == 0f || this.limits.z == 0f)) { maxPossibleSqrRange = long.MaxValue; } else { maxPossibleSqrRange = (long)(Mathf.Max(this.limits.x, Mathf.Max(this.limits.y, Mathf.Max(this.limits.z, this.maxDistance))) * 1000f) + 1L; maxPossibleSqrRange *= maxPossibleSqrRange; } for (int i = 0; i < this.nodes.Length; i++) { if (i % 512 == 0) { yield return(new Progress(Mathf.Lerp(0.15f, 1f, (float)i / (float)this.nodes.Length), "Connecting nodes")); } connections.Clear(); costs.Clear(); PointNode node = this.nodes[i]; if (this.optimizeForSparseGraph) { candidateConnections.Clear(); this.lookupTree.GetInRange(node.position, maxPossibleSqrRange, candidateConnections); Console.WriteLine(i + " " + candidateConnections.Count); for (int n = 0; n < candidateConnections.Count; n++) { PointNode pointNode = candidateConnections[n] as PointNode; float num3; if (pointNode != node && this.IsValidConnection(node, pointNode, out num3)) { connections.Add(pointNode); costs.Add((uint)Mathf.RoundToInt(num3 * 1000f)); } } } else { for (int num4 = 0; num4 < this.nodes.Length; num4++) { if (i != num4) { PointNode pointNode2 = this.nodes[num4]; float num5; if (this.IsValidConnection(node, pointNode2, out num5)) { connections.Add(pointNode2); costs.Add((uint)Mathf.RoundToInt(num5 * 1000f)); } } } } node.connections = connections.ToArray(); node.connectionCosts = costs.ToArray(); } } yield break; }
private void AddToLookup(PointNode node) { this.lookupTree.Add(node); }
// Scan() has been deprecated, replaced by ScanInternal. public override void ScanInternal(OnScanStatus statusCallback) { // ******************************************************************** // NOTE: removed all code that derived nodes from GameObjects and Tags // ******************************************************************** //D.Log("ScanInternal called."); var walkableOpenSpaceWaypoints = GetWalkableOpenSpaceWaypoints(); var unwalkableOpenSpaceWaypoints = GetUnWalkableOpenSpaceWaypoints(); var walkableSystemWaypoints = GetWalkableInteriorSystemWaypoints(); int waypointCount = walkableOpenSpaceWaypoints.Count + unwalkableOpenSpaceWaypoints.Count + walkableSystemWaypoints.Count; // Make the Nodes array nodes = new PointNode[waypointCount]; nodeCount = waypointCount; //for (int nodeIndex = 0; nodeIndex < waypointCount; nodeIndex++) { // nodes[nodeIndex] = new PointNode(active); //} int nextNodeIndex = Constants.Zero; bool isWalkable = true; PopulateNodes(walkableOpenSpaceWaypoints, openSpaceTagMask, isWalkable, ref nextNodeIndex); //D.Log("NextNodeIndex = {0}.", nextNodeIndex); PopulateNodes(walkableSystemWaypoints, systemTagMask, isWalkable, ref nextNodeIndex); //D.Log("NextNodeIndex = {0}.", nextNodeIndex); isWalkable = false; PopulateNodes(unwalkableOpenSpaceWaypoints, openSpaceTagMask, isWalkable, ref nextNodeIndex); //D.Log("NextNodeIndex = {0}.", nextNodeIndex); D.Log("{0} Pathfinding nodes.", nodeCount); if (maxDistance >= 0) { //To avoid too many allocations, these lists are reused for each node List<PointNode> connections = new List<PointNode>(3); List<uint> costs = new List<uint>(3); //Loop through all nodes and add connections to other nodes int connectionCount = 0; int invalidConnectionCount = 0; for (int i = 0; i < nodes.Length; i++) { connections.Clear(); costs.Clear(); PointNode node = nodes[i]; // OPTIMIZE Only brute force is available in the free version for (int j = 0; j < nodes.Length; j++) { if (i == j) { continue; } PointNode other = nodes[j]; float dist = 0; if (IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } else { invalidConnectionCount++; } //else if (dist <= maxDistance) { // maxDistance is currently 700 // invalidConnectionCount++; // D.Warn("Connection from Node at {0} to Node at {1} is invalid.", (Vector3)node.position, (Vector3)other.position); // D.AssertException(false); //} } node.connections = connections.ToArray(); connectionCount += connections.Count; node.connectionCosts = costs.ToArray(); } int totalConnectionsAttempted = connectionCount + invalidConnectionCount; D.Log("{0}/{1} valid connections.", connectionCount, totalConnectionsAttempted); } }
public override NNInfo GetNearestForce(Vector3 position, NNConstraint constraint) { if (nodes == null) { return(new NNInfo()); } float maxDistSqr = constraint.constrainDistance ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity; float minDist = float.PositiveInfinity; GraphNode minNode = null; float minConstDist = float.PositiveInfinity; GraphNode minConstNode = null; if (optimizeForSparseGraph) { Int3 lookupStart = WorldToLookupSpace((Int3)position); Int3 size = lookupStart - minLookup; int mw = 0; mw = System.Math.Max(mw, System.Math.Abs(size.x)); mw = System.Math.Max(mw, System.Math.Abs(size.y)); mw = System.Math.Max(mw, System.Math.Abs(size.z)); size = lookupStart - maxLookup; mw = System.Math.Max(mw, System.Math.Abs(size.x)); mw = System.Math.Max(mw, System.Math.Abs(size.y)); mw = System.Math.Max(mw, System.Math.Abs(size.z)); PointNode node; var searcher = new GetNearestHelper(position, maxDistSqr, constraint, nodeLookup); searcher.Search(lookupStart); for (int w = 1; w <= mw; w++) { if (w >= 20) { Debug.LogWarning("Aborting GetNearest call at maximum distance because it has iterated too many times.\n" + "If you get this regularly, check your settings for PointGraph -> <b>Optimize For Sparse Graph</b> and " + "PointGraph -> <b>Optimize For 2D</b>.\nThis happens when the closest node was very far away (20*link distance between nodes). " + "When optimizing for sparse graphs, getting the nearest node from far away positions is <b>very slow</b>.\n"); break; } if (lookupCellSize.y == 0) { Int3 reference = lookupStart + new Int3(-w, 0, -w); for (int x = 0; x <= 2 * w; x++) { searcher.Search(reference + new Int3(x, 0, 0)); searcher.Search(reference + new Int3(x, 0, 2 * w)); } for (int z = 1; z < 2 * w; z++) { searcher.Search(reference + new Int3(0, 0, z)); searcher.Search(reference + new Int3(2 * w, 0, z)); } } else { Int3 reference = lookupStart + new Int3(-w, -w, -w); for (int x = 0; x <= 2 * w; x++) { for (int y = 0; y <= 2 * w; y++) { searcher.Search(reference + new Int3(x, y, 0)); searcher.Search(reference + new Int3(x, y, 2 * w)); } } for (int z = 1; z < 2 * w; z++) { for (int y = 0; y <= 2 * w; y++) { searcher.Search(reference + new Int3(0, y, z)); searcher.Search(reference + new Int3(2 * w, y, z)); } } for (int x = 1; x < 2 * w; x++) { for (int z = 1; z < 2 * w; z++) { searcher.Search(reference + new Int3(x, 0, z)); searcher.Search(reference + new Int3(x, 2 * w, z)); } } } minConstNode = searcher.minConstNode; minNode = searcher.minNode; minDist = searcher.minDist; minConstDist = searcher.minConstDist; if (minConstNode != null) { // Only search one more layer mw = System.Math.Min(mw, w + 1); } } } else { for (int i = 0; i < nodeCount; i++) { PointNode node = nodes[i]; float dist = (position - (Vector3)node.position).sqrMagnitude; if (dist < minDist) { minDist = dist; minNode = node; } if (constraint == null || (dist < minConstDist && dist < maxDistSqr && constraint.Suitable(node))) { minConstDist = dist; minConstNode = node; } } } var nnInfo = new NNInfo(minNode); nnInfo.constrainedNode = minConstNode; if (minConstNode != null) { nnInfo.constClampedPosition = (Vector3)minConstNode.position; } else if (minNode != null) { nnInfo.constrainedNode = minNode; nnInfo.constClampedPosition = (Vector3)minNode.position; } return(nnInfo); }
// Token: 0x0600051F RID: 1311 RVA: 0x0002C174 File Offset: 0x0002A574 public override NNInfo GetNearestForce(Vector3 position, NNConstraint constraint) { if (this.nodes == null) { return(default(NNInfo)); } float num = (!constraint.constrainDistance) ? float.PositiveInfinity : AstarPath.active.maxNearestNodeDistanceSqr; float num2 = float.PositiveInfinity; GraphNode graphNode = null; float num3 = float.PositiveInfinity; GraphNode graphNode2 = null; if (this.optimizeForSparseGraph) { Int3 @int = this.WorldToLookupSpace((Int3)position); Int3 int2 = @int - this.minLookup; int num4 = 0; num4 = Math.Max(num4, Math.Abs(int2.x)); num4 = Math.Max(num4, Math.Abs(int2.y)); num4 = Math.Max(num4, Math.Abs(int2.z)); int2 = @int - this.maxLookup; num4 = Math.Max(num4, Math.Abs(int2.x)); num4 = Math.Max(num4, Math.Abs(int2.y)); num4 = Math.Max(num4, Math.Abs(int2.z)); PointNode pointNode = null; if (this.nodeLookup.TryGetValue(@int, out pointNode)) { while (pointNode != null) { float sqrMagnitude = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; graphNode = pointNode; } if (constraint == null || (sqrMagnitude < num3 && sqrMagnitude < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude; graphNode2 = pointNode; } pointNode = pointNode.next; } } for (int i = 1; i <= num4; i++) { if (i >= 20) { Debug.LogWarning("Aborting GetNearest call at maximum distance because it has iterated too many times.\nIf you get this regularly, check your settings for PointGraph -> <b>Optimize For Sparse Graph</b> and PointGraph -> <b>Optimize For 2D</b>.\nThis happens when the closest node was very far away (20*link distance between nodes). When optimizing for sparse graphs, getting the nearest node from far away positions is <b>very slow</b>.\n"); break; } if (this.lookupCellSize.y == 0) { Int3 lhs = @int + new Int3(-i, 0, -i); for (int j = 0; j <= 2 * i; j++) { if (this.nodeLookup.TryGetValue(lhs + new Int3(j, 0, 0), out pointNode)) { while (pointNode != null) { float sqrMagnitude2 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude2 < num2) { num2 = sqrMagnitude2; graphNode = pointNode; } if (constraint == null || (sqrMagnitude2 < num3 && sqrMagnitude2 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude2; graphNode2 = pointNode; } pointNode = pointNode.next; } } if (this.nodeLookup.TryGetValue(lhs + new Int3(j, 0, 2 * i), out pointNode)) { while (pointNode != null) { float sqrMagnitude3 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude3 < num2) { num2 = sqrMagnitude3; graphNode = pointNode; } if (constraint == null || (sqrMagnitude3 < num3 && sqrMagnitude3 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude3; graphNode2 = pointNode; } pointNode = pointNode.next; } } } for (int k = 1; k < 2 * i; k++) { if (this.nodeLookup.TryGetValue(lhs + new Int3(0, 0, k), out pointNode)) { while (pointNode != null) { float sqrMagnitude4 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude4 < num2) { num2 = sqrMagnitude4; graphNode = pointNode; } if (constraint == null || (sqrMagnitude4 < num3 && sqrMagnitude4 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude4; graphNode2 = pointNode; } pointNode = pointNode.next; } } if (this.nodeLookup.TryGetValue(lhs + new Int3(2 * i, 0, k), out pointNode)) { while (pointNode != null) { float sqrMagnitude5 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude5 < num2) { num2 = sqrMagnitude5; graphNode = pointNode; } if (constraint == null || (sqrMagnitude5 < num3 && sqrMagnitude5 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude5; graphNode2 = pointNode; } pointNode = pointNode.next; } } } } else { Int3 lhs2 = @int + new Int3(-i, -i, -i); for (int l = 0; l <= 2 * i; l++) { for (int m = 0; m <= 2 * i; m++) { if (this.nodeLookup.TryGetValue(lhs2 + new Int3(l, m, 0), out pointNode)) { while (pointNode != null) { float sqrMagnitude6 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude6 < num2) { num2 = sqrMagnitude6; graphNode = pointNode; } if (constraint == null || (sqrMagnitude6 < num3 && sqrMagnitude6 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude6; graphNode2 = pointNode; } pointNode = pointNode.next; } } if (this.nodeLookup.TryGetValue(lhs2 + new Int3(l, m, 2 * i), out pointNode)) { while (pointNode != null) { float sqrMagnitude7 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude7 < num2) { num2 = sqrMagnitude7; graphNode = pointNode; } if (constraint == null || (sqrMagnitude7 < num3 && sqrMagnitude7 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude7; graphNode2 = pointNode; } pointNode = pointNode.next; } } } } for (int n = 1; n < 2 * i; n++) { for (int num5 = 0; num5 <= 2 * i; num5++) { if (this.nodeLookup.TryGetValue(lhs2 + new Int3(0, num5, n), out pointNode)) { while (pointNode != null) { float sqrMagnitude8 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude8 < num2) { num2 = sqrMagnitude8; graphNode = pointNode; } if (constraint == null || (sqrMagnitude8 < num3 && sqrMagnitude8 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude8; graphNode2 = pointNode; } pointNode = pointNode.next; } } if (this.nodeLookup.TryGetValue(lhs2 + new Int3(2 * i, num5, n), out pointNode)) { while (pointNode != null) { float sqrMagnitude9 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude9 < num2) { num2 = sqrMagnitude9; graphNode = pointNode; } if (constraint == null || (sqrMagnitude9 < num3 && sqrMagnitude9 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude9; graphNode2 = pointNode; } pointNode = pointNode.next; } } } } for (int num6 = 1; num6 < 2 * i; num6++) { for (int num7 = 1; num7 < 2 * i; num7++) { if (this.nodeLookup.TryGetValue(lhs2 + new Int3(num6, 0, num7), out pointNode)) { while (pointNode != null) { float sqrMagnitude10 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude10 < num2) { num2 = sqrMagnitude10; graphNode = pointNode; } if (constraint == null || (sqrMagnitude10 < num3 && sqrMagnitude10 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude10; graphNode2 = pointNode; } pointNode = pointNode.next; } } if (this.nodeLookup.TryGetValue(lhs2 + new Int3(num6, 2 * i, num7), out pointNode)) { while (pointNode != null) { float sqrMagnitude11 = (position - (Vector3)pointNode.position).sqrMagnitude; if (sqrMagnitude11 < num2) { num2 = sqrMagnitude11; graphNode = pointNode; } if (constraint == null || (sqrMagnitude11 < num3 && sqrMagnitude11 < num && constraint.Suitable(pointNode))) { num3 = sqrMagnitude11; graphNode2 = pointNode; } pointNode = pointNode.next; } } } } } if (graphNode2 != null) { num4 = Math.Min(num4, i + 1); } } } else { for (int num8 = 0; num8 < this.nodeCount; num8++) { PointNode pointNode2 = this.nodes[num8]; float sqrMagnitude12 = (position - (Vector3)pointNode2.position).sqrMagnitude; if (sqrMagnitude12 < num2) { num2 = sqrMagnitude12; graphNode = pointNode2; } if (constraint == null || (sqrMagnitude12 < num3 && sqrMagnitude12 < num && constraint.Suitable(pointNode2))) { num3 = sqrMagnitude12; graphNode2 = pointNode2; } } } NNInfo result = new NNInfo(graphNode); result.constrainedNode = graphNode2; if (graphNode2 != null) { result.constClampedPosition = (Vector3)graphNode2.position; } else if (graphNode != null) { result.constrainedNode = graphNode; result.constClampedPosition = (Vector3)graphNode.position; } return(result); }
public void AddToLookup(PointNode node) { if (_nodeLookup == null) { return; } Int3 lookupPosition = WorldToLookupSpace(node.position); if (_nodeLookup.Count == 0) { _minLookup = lookupPosition; _maxLookup = lookupPosition; } else { _minLookup = new Int3(System.Math.Min(_minLookup.x, lookupPosition.x), System.Math.Min(_minLookup.y, lookupPosition.y), System.Math.Min(_minLookup.z, lookupPosition.z)); _maxLookup = new Int3(System.Math.Max(_minLookup.x, lookupPosition.x), System.Math.Max(_minLookup.y, lookupPosition.y), System.Math.Max(_minLookup.z, lookupPosition.z)); } // Does not cover all cases, but at least some of them if (node.next != null) { throw new System.Exception("This node has already been added to the lookup structure."); } PointNode linkedListRoot; if (_nodeLookup.TryGetValue(lookupPosition, out linkedListRoot)) { // Insert in between node.next = linkedListRoot.next; linkedListRoot.next = node; } else { _nodeLookup[lookupPosition] = node; } }
// Token: 0x0600052A RID: 1322 RVA: 0x0002D6B8 File Offset: 0x0002BAB8 public void UpdateArea(GraphUpdateObject guo) { if (this.nodes == null) { return; } for (int i = 0; i < this.nodeCount; i++) { if (guo.bounds.Contains((Vector3)this.nodes[i].position)) { guo.WillUpdateNode(this.nodes[i]); guo.Apply(this.nodes[i]); } } if (guo.updatePhysics) { Bounds bounds = guo.bounds; if (this.thickRaycast) { bounds.Expand(this.thickRaycastRadius * 2f); } List <GraphNode> list = ListPool <GraphNode> .Claim(); List <uint> list2 = ListPool <uint> .Claim(); for (int j = 0; j < this.nodeCount; j++) { PointNode pointNode = this.nodes[j]; Vector3 a = (Vector3)pointNode.position; List <GraphNode> list3 = null; List <uint> list4 = null; for (int k = 0; k < this.nodeCount; k++) { if (k != j) { Vector3 b = (Vector3)this.nodes[k].position; if (Polygon.LineIntersectsBounds(bounds, a, b)) { PointNode pointNode2 = this.nodes[k]; bool flag = pointNode.ContainsConnection(pointNode2); float num; if (!flag && this.IsValidConnection(pointNode, pointNode2, out num)) { if (list3 == null) { list.Clear(); list2.Clear(); list3 = list; list4 = list2; list3.AddRange(pointNode.connections); list4.AddRange(pointNode.connectionCosts); } uint item = (uint)Mathf.RoundToInt(num * 1000f); list3.Add(pointNode2); list4.Add(item); } else if (flag && !this.IsValidConnection(pointNode, pointNode2, out num)) { if (list3 == null) { list.Clear(); list2.Clear(); list3 = list; list4 = list2; list3.AddRange(pointNode.connections); list4.AddRange(pointNode.connectionCosts); } int num2 = list3.IndexOf(pointNode2); if (num2 != -1) { list3.RemoveAt(num2); list4.RemoveAt(num2); } } } } } if (list3 != null) { pointNode.connections = list3.ToArray(); pointNode.connectionCosts = list4.ToArray(); } } ListPool <GraphNode> .Release(list); ListPool <uint> .Release(list2); } }
private void AddNodes(IList<Vector3> waypoints, uint tag, ref int nextNodeIndex) { CheckAndAdjustNodesSize(waypoints.Count); int indexAfterLastNode = nextNodeIndex + waypoints.Count; for (int index = nextNodeIndex; index < indexAfterLastNode; index++) { PointNode node = new PointNode(active); node.SetPosition((Int3)waypoints[index - nextNodeIndex]); node.Walkable = true; node.GraphIndex = graphIndex; node.Tag = tag; nodes[index] = node; nodeCount++; AddToLookup(node); } D.AssertEqual(nodes.Length, nodeCount); nextNodeIndex = indexAfterLastNode; }
void AddToLookup(PointNode node) { // A* Pathfinding Project Pro Only }
private void CheckAndAdjustNodesSize(int additionalNodes) { if (nodes == null || nodeCount == nodes.Length) { //var startTime = Utility.SystemTime; var nds = new PointNode[nodes != null ? nodes.Length + additionalNodes : additionalNodes]; for (int i = 0; i < nodeCount; i++) { nds[i] = nodes[i]; } nodes = nds; //D.Log("{0}.CheckAndAdjustNodesSize({1}) took {2:0.00} seconds.", GetType().Name, additionalNodes, (Utility.SystemTime - startTime).TotalSeconds); } }
public override IEnumerable <Progress> ScanInternal() { yield return(new Progress(0, "Searching for GameObjects")); if (root == null) { //If there is no root object, try to find nodes with the specified tag instead GameObject[] gos = searchTag != null?GameObject.FindGameObjectsWithTag(searchTag) : null; if (gos == null) { nodes = new PointNode[0]; nodeCount = 0; yield break; } yield return(new Progress(0.1f, "Creating nodes")); //Create and set up the found nodes nodes = new PointNode[gos.Length]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } for (int i = 0; i < gos.Length; i++) { nodes[i].SetPosition((Int3)gos[i].transform.position); nodes[i].Walkable = true; nodes[i].gameObject = gos[i].gameObject; } } else { //Search the root for children and create nodes for them if (!recursive) { nodes = new PointNode[root.childCount]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } int c = 0; foreach (Transform child in root) { nodes[c].SetPosition((Int3)child.position); nodes[c].Walkable = true; nodes[c].gameObject = child.gameObject; c++; } } else { nodes = new PointNode[CountChildren(root)]; nodeCount = nodes.Length; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new PointNode(active); } int startID = 0; AddChildren(ref startID, root); } } if (optimizeForSparseGraph) { yield return(new Progress(0.15f, "Building node lookup")); RebuildNodeLookup(); } if (maxDistance >= 0) { // To avoid too many allocations, these lists are reused for each node var connections = new List <PointNode>(); var costs = new List <uint>(); var candidateConnections = new List <GraphNode>(); // Max possible squared length of a connection between two nodes // This is used to speed up the calculations by skipping a lot of nodes that do not need to be checked long maxPossibleSqrRange; if (maxDistance == 0 && (limits.x == 0 || limits.y == 0 || limits.z == 0)) { maxPossibleSqrRange = long.MaxValue; } else { maxPossibleSqrRange = (long)(Mathf.Max(limits.x, Mathf.Max(limits.y, Mathf.Max(limits.z, maxDistance))) * Int3.Precision) + 1; maxPossibleSqrRange *= maxPossibleSqrRange; } // Report progress every N nodes const int YieldEveryNNodes = 512; // Loop through all nodes and add connections to other nodes for (int i = 0; i < nodes.Length; i++) { if (i % YieldEveryNNodes == 0) { yield return(new Progress(Mathf.Lerp(0.15f, 1, i / (float)nodes.Length), "Connecting nodes")); } connections.Clear(); costs.Clear(); PointNode node = nodes[i]; if (optimizeForSparseGraph) { candidateConnections.Clear(); lookupTree.GetInRange(node.position, maxPossibleSqrRange, candidateConnections); System.Console.WriteLine(i + " " + candidateConnections.Count); for (int j = 0; j < candidateConnections.Count; j++) { var other = candidateConnections[j] as PointNode; float dist; if (other != node && IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } } } else { // Only brute force is available in the free version for (int j = 0; j < nodes.Length; j++) { if (i == j) { continue; } PointNode other = nodes[j]; float dist; if (IsValidConnection(node, other, out dist)) { connections.Add(other); /** \todo Is this equal to .costMagnitude */ costs.Add((uint)Mathf.RoundToInt(dist * Int3.FloatPrecision)); } } } node.connections = connections.ToArray(); node.connectionCosts = costs.ToArray(); } } }
// Token: 0x060025BE RID: 9662 RVA: 0x001A1828 File Offset: 0x0019FA28 private IEnumerable <Progress> ConnectNodesAsync() { if (this.maxDistance >= 0f) { List <Connection> connections = new List <Connection>(); List <GraphNode> candidateConnections = new List <GraphNode>(); long maxSquaredRange; if (this.maxDistance == 0f && (this.limits.x == 0f || this.limits.y == 0f || this.limits.z == 0f)) { maxSquaredRange = long.MaxValue; } else { maxSquaredRange = (long)(Mathf.Max(this.limits.x, Mathf.Max(this.limits.y, Mathf.Max(this.limits.z, this.maxDistance))) * 1000f) + 1L; maxSquaredRange *= maxSquaredRange; } int num3; for (int i = 0; i < this.nodeCount; i = num3 + 1) { if (i % 512 == 0) { yield return(new Progress((float)i / (float)this.nodes.Length, "Connecting nodes")); } connections.Clear(); PointNode pointNode = this.nodes[i]; if (this.optimizeForSparseGraph) { candidateConnections.Clear(); this.lookupTree.GetInRange(pointNode.position, maxSquaredRange, candidateConnections); for (int j = 0; j < candidateConnections.Count; j++) { PointNode pointNode2 = candidateConnections[j] as PointNode; float num; if (pointNode2 != pointNode && this.IsValidConnection(pointNode, pointNode2, out num)) { connections.Add(new Connection(pointNode2, (uint)Mathf.RoundToInt(num * 1000f), byte.MaxValue)); } } } else { for (int k = 0; k < this.nodeCount; k++) { if (i != k) { PointNode pointNode3 = this.nodes[k]; float num2; if (this.IsValidConnection(pointNode, pointNode3, out num2)) { connections.Add(new Connection(pointNode3, (uint)Mathf.RoundToInt(num2 * 1000f), byte.MaxValue)); } } } } pointNode.connections = connections.ToArray(); num3 = i; } connections = null; candidateConnections = null; } yield break; }
public void InternalOnPostScan () { if ( EndTransform == null || StartTransform == null ) return; if ( AstarPath.active.astarData.pointGraph == null ) { AstarPath.active.astarData.AddGraph ( new PointGraph () ); } if ( startNode != null) { NodeLink2 tmp; if (reference.TryGetValue (startNode, out tmp) && tmp == this) reference.Remove (startNode); } if ( endNode != null) { NodeLink2 tmp; if (reference.TryGetValue (endNode, out tmp) && tmp == this) reference.Remove (endNode); } //Get nearest nodes from the first point graph, assuming both start and end transforms are nodes startNode = AstarPath.active.astarData.pointGraph.AddNode ( (Int3)StartTransform.position );//AstarPath.active.astarData.pointGraph.GetNearest(StartTransform.position).node as PointNode; endNode = AstarPath.active.astarData.pointGraph.AddNode ( (Int3)EndTransform.position ); //AstarPath.active.astarData.pointGraph.GetNearest(EndTransform.position).node as PointNode; connectedNode1 = null; connectedNode2 = null; if (startNode == null || endNode == null) { startNode = null; endNode = null; return; } postScanCalled = true; reference[startNode] = this; reference[endNode] = this; Apply( true ); }
[Obsolete] // 8.17.16 use my AddNodes(waypoints) public PointNode AddNode(Int3 position) { if (nodes == null || nodeCount == nodes.Length) { var nds = new PointNode[nodes != null ? System.Math.Max(nodes.Length + 4, nodes.Length * 2) : 4]; for (int i = 0; i < nodeCount; i++) nds[i] = nodes[i]; nodes = nds; } PointNode node = new PointNode(active); node.SetPosition(position); node.GraphIndex = graphIndex; node.Walkable = true; nodes[nodeCount] = node; nodeCount++; AddToLookup(node); return node; }
/// <summary> /// Calculates connections for all nodes in the graph. /// This is an IEnumerable, you can iterate through it using e.g foreach to get progress information. /// </summary> IEnumerable <Progress> ConnectNodesAsync() { if (maxDistance >= 0) { // To avoid too many allocations, these lists are reused for each node var connections = new List <Connection>(); var candidateConnections = new List <GraphNode>(); long maxSquaredRange; // Max possible squared length of a connection between two nodes // This is used to speed up the calculations by skipping a lot of nodes that do not need to be checked if (maxDistance == 0 && (limits.x == 0 || limits.y == 0 || limits.z == 0)) { maxSquaredRange = long.MaxValue; } else { maxSquaredRange = (long)(Mathf.Max(limits.x, Mathf.Max(limits.y, Mathf.Max(limits.z, maxDistance))) * Int3.Precision) + 1; maxSquaredRange *= maxSquaredRange; } // Report progress every N nodes const int YieldEveryNNodes = 512; // Loop through all nodes and add connections to other nodes for (int i = 0; i < nodeCount; i++) { if (i % YieldEveryNNodes == 0) { yield return(new Progress(i / (float)nodeCount, "Connecting nodes")); } connections.Clear(); var node = nodes[i]; if (optimizeForSparseGraph) { candidateConnections.Clear(); lookupTree.GetInRange(node.position, maxSquaredRange, candidateConnections); for (int j = 0; j < candidateConnections.Count; j++) { var other = candidateConnections[j] as PointNode; float dist; if (other != node && IsValidConnection(node, other, out dist)) { connections.Add(new Connection( other, /// <summary>TODO: Is this equal to .costMagnitude</summary> (uint)Mathf.RoundToInt(dist * Int3.FloatPrecision) )); } } } else { // Only brute force is available in the free version for (int j = 0; j < nodeCount; j++) { if (i == j) { continue; } PointNode other = nodes[j]; float dist; if (IsValidConnection(node, other, out dist)) { connections.Add(new Connection( other, /// <summary>TODO: Is this equal to .costMagnitude</summary> (uint)Mathf.RoundToInt(dist * Int3.FloatPrecision) )); } } } node.connections = connections.ToArray(); node.SetConnectivityDirty(); } } }
public override void DeserializeExtraInfo(GraphSerializationContext ctx) { int count = ctx.reader.ReadInt32(); if (count == -1) { nodes = null; return; } nodes = new PointNode[count]; nodeCount = count; for (int i = 0; i < nodes.Length; i++) { if (ctx.reader.ReadInt32() == -1) continue; nodes[i] = new PointNode(active); nodes[i].DeserializeNode(ctx); } }
/** Returns if the connection between \a a and \a b is valid. * Checks for obstructions using raycasts (if enabled) and checks for height differences.\n * As a bonus, it outputs the distance between the nodes too if the connection is valid */ private bool IsValidConnection(PointNode a, PointNode b, out float dist) { dist = Constants.ZeroF; if (a.Walkable && b.Walkable) { var dir = (Vector3)(a.position - b.position); dist = dir.magnitude; if (maxDistance == 0 || dist < maxDistance) { return true; } } return false; }
// Token: 0x060025C3 RID: 9667 RVA: 0x001A1AF0 File Offset: 0x0019FCF0 void IUpdatableGraph.UpdateArea(GraphUpdateObject guo) { if (this.nodes == null) { return; } for (int i = 0; i < this.nodeCount; i++) { PointNode pointNode = this.nodes[i]; if (guo.bounds.Contains((Vector3)pointNode.position)) { guo.WillUpdateNode(pointNode); guo.Apply(pointNode); } } if (guo.updatePhysics) { Bounds bounds = guo.bounds; if (this.thickRaycast) { bounds.Expand(this.thickRaycastRadius * 2f); } List <Connection> list = ListPool <Connection> .Claim(); for (int j = 0; j < this.nodeCount; j++) { PointNode pointNode2 = this.nodes[j]; Vector3 a = (Vector3)pointNode2.position; List <Connection> list2 = null; for (int k = 0; k < this.nodeCount; k++) { if (k != j) { Vector3 b = (Vector3)this.nodes[k].position; if (VectorMath.SegmentIntersectsBounds(bounds, a, b)) { PointNode pointNode3 = this.nodes[k]; bool flag = pointNode2.ContainsConnection(pointNode3); float num; bool flag2 = this.IsValidConnection(pointNode2, pointNode3, out num); if (list2 == null && flag != flag2) { list.Clear(); list2 = list; list2.AddRange(pointNode2.connections); } if (!flag && flag2) { uint cost = (uint)Mathf.RoundToInt(num * 1000f); list2.Add(new Connection(pointNode3, cost, byte.MaxValue)); } else if (flag && !flag2) { for (int l = 0; l < list2.Count; l++) { if (list2[l].node == pointNode3) { list2.RemoveAt(l); break; } } } } } } if (list2 != null) { pointNode2.connections = list2.ToArray(); } } ListPool <Connection> .Release(ref list); } }