public GraphNode GetOther ( GraphNode a ) { if ( this.connections.Length < 2 ) return null; if ( this.connections.Length != 2 ) throw new System.Exception ("Invalid NodeLink3Node. Expected 2 connections, found " + this.connections.Length); return a == connections[0] ? (connections[1] as NodeLink3Node).GetOtherInternal(this) : (connections[0] as NodeLink3Node).GetOtherInternal(this); }
/** Enqueue a connection from this node to the specified node. * If the connection already exists, the cost will simply be updated and * no extra connection added. * * \note Only adds a one-way connection. Consider calling the same function on the other node * to get a two-way connection. */ public override void AddConnection (GraphNode node, uint cost) { if (connections != null) { for (int i=0;i<connections.Length;i++) { if (connections[i] == node) { connectionCosts[i] = cost; return; } } } int connLength = connections != null ? connections.Length : 0; var newconns = new GraphNode[connLength+1]; var newconncosts = new uint[connLength+1]; for (int i=0;i<connLength;i++) { newconns[i] = connections[i]; newconncosts[i] = connectionCosts[i]; } newconns[connLength] = node; newconncosts[connLength] = cost; connections = newconns; connectionCosts = newconncosts; }
public override bool GetPortal (GraphNode other, List<Vector3> left, List<Vector3> right, bool backwards) { if ( this.connections.Length < 2 ) return false; if ( this.connections.Length != 2 ) throw new System.Exception ("Invalid NodeLink3Node. Expected 2 connections, found " + this.connections.Length); //if ( other != connections[0] || other != connections[1] ) return false; if ( left != null ) { //Debug.DrawLine ( portalA, portalB, Color.red); left.Add ( portalA ); right.Add ( portalB ); /* Vector3 normal = link.transform.forward; Vector3 tangent = Vector3.Dot (normal, (Vector3)(other.Position - this.Position) ) > 0 ? link.transform.right*0.5f : -link.transform.right*0.5f; Debug.DrawLine ( link.transform.position -tangent * link.portalWidth, link.transform.position +tangent * link.portalWidth, Color.red); Debug.DrawRay ( link.transform.position -tangent * link.portalWidth, Vector3.up*5, Color.red); Debug.Break (); left.Enqueue ( link.transform.position -tangent * link.portalWidth ); right.Enqueue (link.transform.position +tangent * link.portalWidth );*/ } return true; }
/** 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 * * \returns True if the given nodes are still reachable from each other after the \a guo has been applied. False otherwise. * \code var guo = new GraphUpdateObject (tower.GetComponent<Collider>.bounds); var spawnPointNode = AstarPath.active.GetNearest (spawnPoint.position).node; var goalNode = AstarPath.active.GetNearest (goalNode.position).node; if (GraphUpdateUtilities.UpdateGraphsNoBlock (guo, spawnPointNode, goalNode, false)) { // Valid tower position // Since the last parameter (which is called "alwaysRevert") in the method call was false // The graph is now updated and the game can just continue } else { // Invalid tower position. It blocks the path between the spawn point and the goal // The effect on the graph has been reverted Destroy (tower); } \endcode */ 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; }
// Update is called once per frame void LateUpdate () { if (prevNode == null) { NNInfo nninfo = AstarPath.active.GetNearest (transform.position); prevNode = nninfo.node; prevPos = transform.position; } if (prevNode == null) { return; } if (prevNode != null) { IRaycastableGraph graph = AstarData.GetGraph (prevNode) as IRaycastableGraph; if (graph != null) { GraphHitInfo hit; if (graph.Linecast (prevPos,transform.position,prevNode, out hit)) { hit.point.y = transform.position.y; Vector3 closest = AstarMath.NearestPoint (hit.tangentOrigin,hit.tangentOrigin+hit.tangent,transform.position); Vector3 ohit = hit.point; ohit = ohit + Vector3.ClampMagnitude((Vector3)hit.node.position-ohit,0.008f); if (graph.Linecast (ohit,closest,hit.node, out hit)) { hit.point.y = transform.position.y; transform.position = hit.point; } else { closest.y = transform.position.y; transform.position = closest; } } prevNode = hit.node; } } prevPos = transform.position; }
/** Returns if the node is in the search tree of the path. * Only guaranteed to be correct if \a path is the latest path calculated. * Use for gizmo drawing only. */ public static bool InSearchTree (GraphNode node, Path path) { if (path == null || path.pathHandler == null) return true; PathNode nodeR = path.pathHandler.GetPathNode (node); return nodeR.pathID == path.pathID; }
/** Returns the nearest node to a position using the specified NNConstraint. * \param position The position to try to find a close node to * \param hint Can be passed to enable some graph generators to find the nearest node faster. * \param constraint Can for example tell the function to try to return a walkable node. If you do not get a good node back, consider calling GetNearestForce. */ public virtual NNInfo GetNearest (Vector3 position, NNConstraint constraint, GraphNode hint) { // This is a default implementation and it is pretty slow // Graphs usually override this to provide faster and more specialised implementations float maxDistSqr = constraint.constrainDistance ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity; float minDist = float.PositiveInfinity; GraphNode minNode = null; float minConstDist = float.PositiveInfinity; GraphNode minConstNode = null; // Loop through all nodes and find the closest suitable node GetNodes (node => { float dist = (position-(Vector3)node.position).sqrMagnitude; if (dist < minDist) { minDist = dist; minNode = node; } if (dist < minConstDist && dist < maxDistSqr && constraint.Suitable (node)) { minConstDist = dist; minConstNode = node; } return true; }); 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; }
public override bool GetPortal (GraphNode _other, System.Collections.Generic.List<Vector3> left, System.Collections.Generic.List<Vector3> right, bool backwards) { int aIndex, bIndex; return GetPortal (_other,left,right,backwards, out aIndex, out bIndex); }
/** Returns the graph which contains the specified node. * The graph must be in the #graphs array. * * \returns Returns the graph which contains the node. Null if the graph wasn't found */ public static NavGraph GetGraph (GraphNode node) { if (node == null) return null; AstarPath script = AstarPath.active; if (script == null) return null; AstarData data = script.astarData; if (data == null) return null; if (data.graphs == null) return null; uint graphIndex = node.GraphIndex; if (graphIndex >= data.graphs.Length) { return null; } return data.graphs[(int)graphIndex]; }
public override bool Suitable (GraphNode node) { return base.Suitable (node) && path.HasPathTo (node); }
/** Reset all values to their default values. * * \note All inheriting path types (e.g ConstantPath, RandomPath, etc.) which declare their own variables need to * override this function, resetting ALL their variables to enable recycling of paths. * If this is not done, trying to use that path type for pooling might result in weird behaviour. * The best way is to reset to default values the variables declared in the extended path type and then * call this base function in inheriting types with base.Reset (). * * \warning This function should not be called manually. */ public virtual void Reset () { #if ASTAR_POOL_DEBUG pathTraceInfo = "This path was got from the pool or created from here (stacktrace):\n"; pathTraceInfo += System.Environment.StackTrace; #endif if (System.Object.ReferenceEquals (AstarPath.active, null)) throw new System.NullReferenceException ("No AstarPath object found in the scene. " + "Make sure there is one or do not create paths in Awake"); hasBeenReset = true; state = (int)PathState.Created; releasedNotSilent = false; pathHandler = null; callback = null; _errorLog = ""; pathCompleteState = PathCompleteState.NotCalculated; path = ListPool<GraphNode>.Claim(); vectorPath = ListPool<Vector3>.Claim(); currentR = null; duration = 0; searchIterations = 0; searchedNodes = 0; //calltime nnConstraint = PathNNConstraint.Default; next = null; heuristic = AstarPath.active.heuristic; heuristicScale = AstarPath.active.heuristicScale; enabledTags = -1; tagPenalties = null; callTime = System.DateTime.UtcNow; pathID = AstarPath.active.GetNextPathID (); hTarget = Int3.zero; hTargetNode = null; }
/** Returns whether or not the node conforms to this NNConstraint's rules */ public virtual bool Suitable (GraphNode node) { if (constrainWalkability && node.Walkable != walkable) return false; if (constrainArea && area >= 0 && node.Area != area) return false; if (constrainTags && ((tags >> (int)node.Tag) & 0x1) == 0) return false; return true; }
public GraphHitInfo (Vector3 point) { tangentOrigin = Vector3.zero; origin = Vector3.zero; this.point = point; node = null; tangent = Vector3.zero; //this.distance = distance; }
public override void RemoveConnection (GraphNode node) { throw new System.NotImplementedException("QuadTree Nodes do not have support for adding manual connections"); }
/** Prepares the path. Searches for start and end nodes and does some simple checking if a path is at all possible */ public override void Prepare () { AstarProfiler.StartProfile ("Get Nearest"); //Initialize the NNConstraint nnConstraint.tags = enabledTags; NNInfo startNNInfo = AstarPath.active.GetNearest (startPoint,nnConstraint, startHint); //Tell the NNConstraint which node was found as the start node if it is a PathNNConstraint and not a normal NNConstraint var pathNNConstraint = nnConstraint as PathNNConstraint; if (pathNNConstraint != null) { pathNNConstraint.SetStart (startNNInfo.node); } startPoint = startNNInfo.clampedPosition; startIntPoint = (Int3)startPoint; startNode = startNNInfo.node; //If it is declared that this path type has an end point //Some path types might want to use most of the ABPath code, but will not have an explicit end point at this stage if (hasEndPoint) { NNInfo endNNInfo = AstarPath.active.GetNearest (endPoint,nnConstraint, endHint); endPoint = endNNInfo.clampedPosition; // Note, other methods assume hTarget is (Int3)endPoint hTarget = (Int3)endPoint; endNode = endNNInfo.node; hTargetNode = endNode; } AstarProfiler.EndProfile (); #if ASTARDEBUG if (startNode != null) Debug.DrawLine ((Vector3)startNode.position,startPoint,Color.blue); if (endNode != null) Debug.DrawLine ((Vector3)endNode.position,endPoint,Color.blue); #endif if (startNode == null && (hasEndPoint && endNode == null)) { Error (); LogError ("Couldn't find close nodes to the start point or the end point"); return; } if (startNode == null) { Error (); LogError ("Couldn't find a close node to the start point"); return; } if (endNode == null && hasEndPoint) { Error (); LogError ("Couldn't find a close node to the end point"); return; } if (!startNode.Walkable) { #if ASTARDEBUG Debug.DrawRay (startPoint,Vector3.up,Color.red); Debug.DrawLine (startPoint,(Vector3)startNode.position,Color.red); #endif Error (); LogError ("The node closest to the start point is not walkable"); return; } if (hasEndPoint && !endNode.Walkable) { Error (); LogError ("The node closest to the end point is not walkable"); return; } if (hasEndPoint && startNode.Area != endNode.Area) { Error (); LogError ("There is no valid path to the target (start area: "+startNode.Area+", target area: "+endNode.Area+")"); return; } }
public uint GetTraversalCost (GraphNode node) { #if ASTAR_NO_TRAVERSAL_COST return 0; #else unchecked { return GetTagPenalty ((int)node.Tag ) + node.Penalty ; } #endif }
/** May be called by graph nodes to get a special cost for some connections. * Nodes may call it when PathNode.flag2 is set to true, for example mesh nodes, which have * a very large area can be marked on the start and end nodes, this method will be called * to get the actual cost for moving from the start position to its neighbours instead * of as would otherwise be the case, from the start node's position to its neighbours. * The position of a node and the actual start point on the node can vary quite a lot. * * The default behaviour of this method is to return the previous cost of the connection, * essentiall making no change at all. * * This method should return the same regardless of the order of a and b. * That is f(a,b) == f(b,a) should hold. * * \param a Moving from this node * \param b Moving to this node * \param currentCost The cost of moving between the nodes. Return this value if there is no meaningful special cost to return. */ public virtual uint GetConnectionSpecialCost (GraphNode a, GraphNode b, uint currentCost) { return currentCost; }
/** Called after the start node has been found. This is used to get different search logic for the start and end nodes in a path */ public virtual void SetStart (GraphNode node) { if (node != null) { area = (int)node.Area; } else { constrainArea = false; } }
/** Traces the calculated path from the start node to the end. * This will build an array (#path) of the nodes this path will pass through and also set the #vectorPath array to the #path arrays positions. * This implementation will use the #flood (FloodPath) to trace the path from precalculated data. */ public void Trace (GraphNode from) { GraphNode c = from; int count = 0; while (c != null) { path.Add (c); vectorPath.Add ((Vector3)c.position); c = flood.GetParent(c); count++; if (count > 1024) { Debug.LogWarning ("Inifinity loop? >1024 node path. Remove this message if you really have that long paths (FloodPathTracer.cs, Trace function)"); break; } } }
public NNInfo (GraphNode node) { this.node = node; constrainedNode = null; clampedPosition = Vector3.zero; constClampedPosition = Vector3.zero; UpdateInfo (); }
/** Check if a straight path between v1 and v2 is valid */ public bool ValidateLine (GraphNode n1, GraphNode n2, Vector3 v1, Vector3 v2) { if (useRaycasting) { // Use raycasting to check if a straight path between v1 and v2 is valid if (thickRaycast && thickRaycastRadius > 0) { RaycastHit hit; if (Physics.SphereCast (v1+raycastOffset, thickRaycastRadius,v2-v1,out hit, (v2-v1).magnitude,mask)) { return false; } } else { RaycastHit hit; if (Physics.Linecast (v1+raycastOffset,v2+raycastOffset,out hit, mask)) { return false; } } } if (useGraphRaycasting && n1 == null) { n1 = AstarPath.active.GetNearest (v1).node; n2 = AstarPath.active.GetNearest (v2).node; } if (useGraphRaycasting && n1 != null && n2 != null) { // Use graph raycasting to check if a straight path between v1 and v2 is valid NavGraph graph = AstarData.GetGraph (n1); NavGraph graph2 = AstarData.GetGraph (n2); if (graph != graph2) { return false; } if (graph != null) { var rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { if (rayGraph.Linecast (v1,v2, n1)) { return false; } } } } return true; }
/** Sets the constrained node */ public void SetConstrained (GraphNode constrainedNode, Vector3 clampedPosition) { this.constrainedNode = constrainedNode; constClampedPosition = clampedPosition; }
/** Returns the edge which is shared with \a other. * If no edge is shared, -1 is returned. * The edge is GetVertex(result) - GetVertex((result+1) % GetVertexCount()). * See GetPortal for the exact segment shared. * \note Might return that an edge is shared when the two nodes are in different tiles and adjacent on the XZ plane, but on the Y-axis. * Therefore it is recommended that you only test for neighbours of this node or do additional checking afterwards. */ public int SharedEdge (GraphNode other) { int a, b; GetPortal(other, null, null, false, out a, out b); return a; }
/** 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 bool GetPortal (GraphNode _other, System.Collections.Generic.List<Vector3> left, System.Collections.Generic.List<Vector3> right, bool backwards, out int aIndex, out int bIndex) { aIndex = -1; bIndex = -1; //If the nodes are in different graphs, this function has no idea on how to find a shared edge. if (_other.GraphIndex != GraphIndex) return false; // Since the nodes are in the same graph, they are both TriangleMeshNodes // So we don't need to care about other types of nodes var other = _other as TriangleMeshNode; //Get tile indices int tileIndex = (GetVertexIndex(0) >> RecastGraph.TileIndexOffset) & RecastGraph.TileIndexMask; int tileIndex2 = (other.GetVertexIndex(0) >> RecastGraph.TileIndexOffset) & RecastGraph.TileIndexMask; //When the nodes are in different tiles, the edges might not be completely identical //so another technique is needed //Only do this on recast graphs if (tileIndex != tileIndex2 && ( GetNavmeshHolder(GraphIndex) is RecastGraph)) { for ( int i=0;i<connections.Length;i++) { if ( connections[i].GraphIndex != GraphIndex ) { #if !ASTAR_NO_POINT_GRAPH var mid = connections[i] as NodeLink3Node; if ( mid != null && mid.GetOther (this) == other ) { // We have found a node which is connected through a NodeLink3Node if ( left != null ) { mid.GetPortal ( other, left, right, false ); return true; } } #endif } } //Get the tile coordinates, from them we can figure out which edge is going to be shared int x1, x2, z1, z2; int coord; INavmeshHolder nm = GetNavmeshHolder (GraphIndex); nm.GetTileCoordinates(tileIndex, out x1, out z1); nm.GetTileCoordinates(tileIndex2, out x2, out z2); if (System.Math.Abs(x1-x2) == 1) coord = 0; else if (System.Math.Abs(z1-z2) == 1) coord = 2; else throw new System.Exception ("Tiles not adjacent (" + x1+", " + z1 +") (" + x2 + ", " + z2+")"); int av = GetVertexCount (); int bv = other.GetVertexCount (); //Try the X and Z coordinate. For one of them the coordinates should be equal for one of the two nodes' edges //The midpoint between the tiles is the only place where they will be equal int first = -1, second = -1; //Find the shared edge for (int a=0;a<av;a++) { int va = GetVertex(a)[coord]; for (int b=0;b<bv;b++) { if (va == other.GetVertex((b+1)%bv)[coord] && GetVertex((a+1) % av)[coord] == other.GetVertex(b)[coord]) { first = a; second = b; a = av; break; } } } aIndex = first; bIndex = second; if (first != -1) { Int3 a = GetVertex(first); Int3 b = GetVertex((first+1)%av); //The coordinate which is not the same for the vertices int ocoord = coord == 2 ? 0 : 2; //When the nodes are in different tiles, they might not share exactly the same edge //so we clamp the portal to the segment of the edges which they both have. int mincoord = System.Math.Min(a[ocoord], b[ocoord]); int maxcoord = System.Math.Max(a[ocoord], b[ocoord]); mincoord = System.Math.Max (mincoord, System.Math.Min(other.GetVertex(second)[ocoord], other.GetVertex((second+1)%bv)[ocoord])); maxcoord = System.Math.Min (maxcoord, System.Math.Max(other.GetVertex(second)[ocoord], other.GetVertex((second+1)%bv)[ocoord])); if (a[ocoord] < b[ocoord]) { a[ocoord] = mincoord; b[ocoord] = maxcoord; } else { a[ocoord] = maxcoord; b[ocoord] = mincoord; } if (left != null) { //All triangles should be clockwise so second is the rightmost vertex (seen from this node) left.Add ((Vector3)a); right.Add ((Vector3)b); } return true; } } else if (!backwards) { int first = -1; int second = -1; int av = GetVertexCount (); int bv = other.GetVertexCount (); /** \todo Maybe optimize with pa=av-1 instead of modulus... */ for (int a=0;a<av;a++) { int va = GetVertexIndex(a); for (int b=0;b<bv;b++) { if (va == other.GetVertexIndex((b+1)%bv) && GetVertexIndex((a+1) % av) == other.GetVertexIndex(b)) { first = a; second = b; a = av; break; } } } aIndex = first; bIndex = second; if (first != -1) { if (left != null) { //All triangles should be clockwise so second is the rightmost vertex (seen from this node) left.Add ((Vector3)GetVertex(first)); right.Add ((Vector3)GetVertex((first+1)%av)); } } else { for ( int i=0;i<connections.Length;i++) { if ( connections[i].GraphIndex != GraphIndex ) { #if !ASTAR_NO_POINT_GRAPH var mid = connections[i] as NodeLink3Node; if ( mid != null && mid.GetOther (this) == other ) { // We have found a node which is connected through a NodeLink3Node if ( left != null ) { mid.GetPortal ( other, left, right, false ); return true; } } #endif } } return false; } } return true; }
/** Updates the specified node using this GUO's settings */ public virtual void Apply (GraphNode node) { if (shape == null || shape.Contains (node)) { //Update penalty and walkability node.Penalty = (uint)(node.Penalty+addPenalty); if (modifyWalkability) { node.Walkable = setWalkability; } //Update tags if (modifyTag) node.Tag = (uint)setTag; } }
/* Color to use for gizmos. * Returns a color to be used for the specified node with the current debug settings (editor only). * * \version Since 3.6.1 this method will not handle null nodes */ public virtual Color NodeColor (GraphNode node, PathHandler data) { #if !PhotonImplementation Color c = AstarColor.NodeConnection; switch (AstarPath.active.debugMode) { case GraphDebugMode.Areas: c = AstarColor.GetAreaColor (node.Area); break; case GraphDebugMode.Penalty: c = Color.Lerp (AstarColor.ConnectionLowLerp,AstarColor.ConnectionHighLerp, ((float)node.Penalty-AstarPath.active.debugFloor) / (AstarPath.active.debugRoof-AstarPath.active.debugFloor)); break; case GraphDebugMode.Tags: c = AstarMath.IntToColor ((int)node.Tag,0.5F); break; default: if (data == null) return AstarColor.NodeConnection; PathNode nodeR = data.GetPathNode (node); switch (AstarPath.active.debugMode) { case GraphDebugMode.G: c = Color.Lerp (AstarColor.ConnectionLowLerp,AstarColor.ConnectionHighLerp, ((float)nodeR.G-AstarPath.active.debugFloor) / (AstarPath.active.debugRoof-AstarPath.active.debugFloor)); break; case GraphDebugMode.H: c = Color.Lerp (AstarColor.ConnectionLowLerp,AstarColor.ConnectionHighLerp, ((float)nodeR.H-AstarPath.active.debugFloor) / (AstarPath.active.debugRoof-AstarPath.active.debugFloor)); break; case GraphDebugMode.F: c = Color.Lerp (AstarColor.ConnectionLowLerp,AstarColor.ConnectionHighLerp, ((float)nodeR.F-AstarPath.active.debugFloor) / (AstarPath.active.debugRoof-AstarPath.active.debugFloor)); break; } break; } c.a *= 0.5F; return c; #else return new Color (1,1,1); #endif }
public uint CalculateHScore (GraphNode node) { uint v1; uint v2; switch (heuristic) { case Heuristic.Euclidean: v1 = (uint)(((GetHTarget () - node.position).costMagnitude)*heuristicScale); v2 = hTargetNode != null ? AstarPath.active.euclideanEmbedding.GetHeuristic ( node.NodeIndex, hTargetNode.NodeIndex ) : 0; return System.Math.Max (v1,v2); case Heuristic.Manhattan: Int3 p2 = node.position; v1 = (uint)((System.Math.Abs (hTarget.x-p2.x) + System.Math.Abs (hTarget.y-p2.y) + System.Math.Abs (hTarget.z-p2.z))*heuristicScale); v2 = hTargetNode != null ? AstarPath.active.euclideanEmbedding.GetHeuristic ( node.NodeIndex, hTargetNode.NodeIndex ) : 0; return System.Math.Max (v1,v2); case Heuristic.DiagonalManhattan: Int3 p = GetHTarget () - node.position; p.x = System.Math.Abs (p.x); p.y = System.Math.Abs (p.y); p.z = System.Math.Abs (p.z); int diag = System.Math.Min (p.x,p.z); int diag2 = System.Math.Max (p.x,p.z); v1 = (uint)((((14*diag)/10) + (diag2-diag) + p.y) * heuristicScale); v2 = hTargetNode != null ? AstarPath.active.euclideanEmbedding.GetHeuristic ( node.NodeIndex, hTargetNode.NodeIndex ) : 0; return System.Math.Max (v1,v2); } return 0U; }
public bool Contains (GraphNode node) { return Contains((Vector3)node.position); }
/** Returns if the node can be traversed. * This per default equals to if the node is walkable and if the node's tag is included in #enabledTags */ public bool CanTraverse (GraphNode node) { unchecked { return node.Walkable && (enabledTags >> (int)node.Tag & 0x1) != 0; } }