public virtual void OnPathComplete(Path _p) { ABPath abpath = _p as ABPath; if (abpath == null) { throw new Exception("This function only handles ABPaths, do not use special path types"); } this.canSearchAgain = true; abpath.Claim(this); if (abpath.error) { abpath.Release(this, false); return; } if (this.path != null) { this.path.Release(this, false); } this.path = abpath; if (this.path.vectorPath.Count == 1) { this.path.vectorPath.Add(this.path.vectorPath[0]); } this.interpolator.SetPath(this.path.vectorPath); ITransformedGraph transformedGraph = AstarData.GetGraph(this.path.path[0]) as ITransformedGraph; this.movementPlane = ((transformedGraph == null) ? GraphTransform.identityTransform : transformedGraph.transform); this.TargetReached = false; this.interpolator.MoveToLocallyClosestPoint((this.GetFeetPosition() + abpath.originalStartPoint) * 0.5f, true, true); this.interpolator.MoveToLocallyClosestPoint(this.GetFeetPosition(), true, true); }
private void OnPathComplete(Path path) { path.Claim(this); _isSearchingPath = false; _isAtDestination = false; if (path.error) { path.Release(this); return; } if (_path != null) { _path.Release(this); } _path = path as ABPath; var graph = AstarData.GetGraph(path.path[0]) as ITransformedGraph; _movementPlane = graph != null ? graph.transform : GraphTransform.identityTransform; if (_path.vectorPath.Count == 1) { _path.vectorPath.Add(_path.vectorPath[0]); } _interpolator.SetPath(_path.vectorPath); var position = transform.position; _interpolator.MoveToLocallyClosestPoint((position + _path.originalStartPoint) * 0.5f); _interpolator.MoveToLocallyClosestPoint(position); }
public static bool isCollide(VInt3 origin, VInt3 end) { GraphNode startNode = AstarPath.active.GetNearest(origin).node; var graph = AstarData.GetGraph(startNode) as NavmeshBase; return(graph.Linecast(origin, end, startNode)); }
// will return the point at which the line exits the nav mesh, or 'to' if the line does not exit the nav mesh // if 'clampFromInNavMesh' is true, we make sure the from position is on the nav mesh before doing checks // (done in 2d, does not currently support nav meshes on top of one and other) public static Vector3 CalculateExitPointOfRecastGraph(ref Vector3 from, Vector3 to, bool clampFromInNavMesh = false) { NNInfo fromInfo = AstarPath.active.GetNearest(from); if (null == fromInfo.node) { return(from); } if (clampFromInNavMesh) { from = CalculatePointOnRecastGraph(from, 0.1f, fromInfo); } NavGraph graph = AstarData.GetGraph(fromInfo.node); if (graph != null) { IRaycastableGraph rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { GraphHitInfo hit; if (rayGraph.Linecast(from, to, fromInfo.node, out hit)) { return(hit.point); } return(to); // no nav mesh exit } return(from); // no recast graph } return(from); // no nav mesh }
public bool ValidateLine(Node n1, Node n2, Vector3 v1, Vector3 v2) { if (useRaycasting) { if (thickRaycast && thickRaycastRadius > 0) { RaycastHit hit; if (Physics.SphereCast(v1 + raycastOffset, thickRaycastRadius, v2 - v1, out hit, (v2 - v1).magnitude, mask)) { //Debug.DrawRay (hit.point,Vector3.up*5,Color.yellow); return(false); } } else { RaycastHit hit; if (Physics.Linecast(v1 + raycastOffset, v2 + raycastOffset, out hit, mask)) { //Debug.DrawRay (hit.point,Vector3.up*5,Color.yellow); return(false); } } } if (useGraphRaycasting && n1 == null) { n1 = AstarPath.active.GetNearest(v1); n2 = AstarPath.active.GetNearest(v2); } if (useGraphRaycasting && n1 != null && n2 != null) { NavGraph graph = AstarData.GetGraph(n1); NavGraph graph2 = AstarData.GetGraph(n2); if (graph != graph2) { return(false); } if (graph != null) { IRaycastableGraph rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { if (rayGraph.Linecast(v1, v2, n1)) { return(false); } } } } return(true); }
/** Called when a requested path has finished calculation. * A path is first requested by #SearchPath, it is then calculated, probably in the same or the next frame. * Finally it is returned to the seeker which forwards it to this function.\n */ public virtual void OnPathComplete(Path _p) { ABPath p = _p as ABPath; if (p == null) { throw new System.Exception("This function only handles ABPaths, do not use special path types"); } canSearchAgain = true; // Claim the new path p.Claim(this); // Path couldn't be calculated of some reason. // More info in p.errorLog (debug string) if (p.error) { p.Release(this); return; } // Release the previous path if (path != null) { path.Release(this); } // Replace the old path path = p; // Make sure the path contains at least 2 points if (path.vectorPath.Count == 1) { path.vectorPath.Add(path.vectorPath[0]); } interpolator.SetPath(path.vectorPath); var graph = AstarData.GetGraph(path.path[0]) as ITransformedGraph; movementPlane = graph != null ? graph.transform : GraphTransform.identityTransform; // Reset some variables TargetReached = false; // Simulate movement from the point where the path was requested // to where we are right now. This reduces the risk that the agent // gets confused because the first point in the path is far away // from the current position (possibly behind it which could cause // the agent to turn around, and that looks pretty bad). interpolator.MoveToLocallyClosestPoint((GetFeetPosition() + p.originalStartPoint) * 0.5f); interpolator.MoveToLocallyClosestPoint(GetFeetPosition()); }
// checks to see if their is an obstacle between the point and the center of the closest node on the nav mesh public static bool IsPointOnRecastGraph(Vector3 point, NNInfo?nearestInfo = null) { NNInfo info = nearestInfo ?? AstarPath.active.GetNearest(point); NavGraph graph = AstarData.GetGraph(info.node); if (graph != null) { IRaycastableGraph rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { GraphHitInfo hit; return(!rayGraph.Linecast(((Vector3)info.node.position), point, info.node, out hit)); } return(false); // no recast graph } return(false); // no nav mesh }
// 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 = Mathfx.NearestPoint(hit.tangentOrigin, hit.tangentOrigin + hit.tangent, transform.position); if (graph.Linecast(hit.point, 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; }
// Use this for initialization void Start() { //Debug.Log("---2---" + gameObject.isStatic); style = new GUIStyle() { fontSize = 22, alignment = TextAnchor.MiddleCenter, normal = new GUIStyleState() { textColor = Color.white } }; //dynamicRoot = GameObject.Find("DynamicObstacles").transform; //seeker = GetComponent<Seeker>(); /*wallRoot = GameObject.Find("Wall").transform; * playersRoot = GameObject.Find("Players").transform; * robotRoot = GameObject.Find("Robots").transform;*/ pointRoot = GameObject.Find("Points").transform; ball = GameObject.Find("Ball"); //获取当前点所在的图形节点 GraphNode startNode = AstarPath.active.GetNearest((VInt3)pointRoot.GetChild(0).position).node; var other = startNode as TriangleMeshNode; GameObject go4 = Instantiate(ball); go4.transform.position = (Vector3)startNode.position; Debug.Log("--0--" + startNode.position); GraphHitInfo hit = new GraphHitInfo(); var graph = AstarData.GetGraph(startNode) as NavmeshBase; bool canReach = graph.Linecast((VInt3)pointRoot.GetChild(0).position, (VInt3)pointRoot.GetChild(2).position, startNode, out hit); Debug.Log($"---hit point--{hit.point}--{canReach}"); GameObject go5 = Instantiate(ball); go5.transform.position = (Vector3)hit.point; //seeker.StartPath((VInt3)pointRoot.GetChild(0).position, (VInt3)pointRoot.GetChild(2).position, OnPathComplete); }
public Vector3 GetClampedPoint(Vector3 from, Vector3 to, Node hint) { //float minDistance = Mathf.Infinity; Vector3 minPoint = to; if (useRaycasting) { RaycastHit hit; if (Physics.Linecast(from, to, out hit, mask)) { minPoint = hit.point; //minDistance = hit.distance; } } if (useGraphRaycasting && hint != null) { NavGraph graph = AstarData.GetGraph(hint); if (graph != null) { IRaycastableGraph rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { GraphHitInfo hit; if (rayGraph.Linecast(from, minPoint, hint, out hit)) { //if ((hit.point-from).magnitude < minDistance) { minPoint = hit.point; //} } } } } return(minPoint); }
// will return false if any part of the line is off the nav mesh // if 'clampFromInNavMesh' is true, we make sure the from position is on the nav mesh before doing checks // (done in 2d, does not currently support nav meshes on top of one and other) public static bool IsVisibleOnRecastGraph(Vector3 from, Vector3 to, bool clampFromInNavMesh = false, NNInfo?nearestInfo = null) { if (null == AstarPath.active) { return(false); } NNInfo fromInfo = nearestInfo ?? AstarPath.active.GetNearest(from); if (null == fromInfo.node) { return(false); } if (clampFromInNavMesh) { from = CalculatePointOnRecastGraph(from, 0.1f, fromInfo); } NavGraph graph = AstarData.GetGraph(fromInfo.node); if (graph != null) { IRaycastableGraph rayGraph = graph as IRaycastableGraph; if (rayGraph != null) { GraphHitInfo hit; if (rayGraph.Linecast(from, to, fromInfo.node, out hit)) { return(false); // hit an obstacle } return(true); // no nav mesh exit } return(false); // no recast graph } return(false); // no nav mesh }
public void OnConstantPathComplete(Path p) { ConstantPath constPath = p as ConstantPath; List <GraphNode> nodes = constPath.allNodes; MoveableNodes = nodes; Mesh mesh = new Mesh(); List <Vector3> verts = new List <Vector3> (); bool drawRaysInstead = false; List <Vector3> pts = Pathfinding.PathUtilities.GetPointsOnNodes(nodes, 20, 0); Vector3 avg = Vector3.zero; for (int i = 0; i < pts.Count; i++) { Debug.DrawRay(pts [i], Vector3.up * 5, Color.red, 3); avg += pts [i]; } if (pts.Count > 0) { avg /= pts.Count; } for (int i = 0; i < pts.Count; i++) { pts [i] -= avg; } Pathfinding.PathUtilities.GetPointsAroundPoint(transform.position, AstarPath.active.astarData.graphs [0] as IRaycastableGraph, pts, 0, 1); for (int i = 0; i < pts.Count; i++) { Debug.DrawRay(pts [i], Vector3.up * 5, Color.blue, 3); } //This will loop through the nodes from furthest away to nearest, not really necessary... but why not :D //Note that the reverse does not, as common sense would suggest, loop through from the closest to the furthest away //since is might contain duplicates and only the node duplicate placed at the highest index is guarenteed to be ordered correctly. for (int i = nodes.Count - 1; i >= 0; i--) { Vector3 pos = (Vector3)nodes [i].position + PathOffset; if (verts.Count == 65000 && !drawRaysInstead) { Debug.LogError("Too many nodes, rendering a mesh would throw 65K vertex error. Using Debug.DrawRay instead for the rest of the nodes"); drawRaysInstead = true; } if (drawRaysInstead) { Debug.DrawRay(pos, Vector3.up, Color.blue); continue; } //Add vertices in a square GridGraph gg = AstarData.GetGraph(nodes [i]) as GridGraph; float scale = 1F; if (gg != null) { scale = gg.nodeSize; } verts.Add(pos + new Vector3(-0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(-0.5F, 0, 0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, 0.5F) * scale); } //Build triangles for the squares Vector3[] vs = verts.ToArray(); int[] tris = new int[(3 * vs.Length) / 2]; for (int i = 0, j = 0; i < vs.Length; j += 6, i += 4) { tris [j + 0] = i; tris [j + 1] = i + 1; tris [j + 2] = i + 2; tris [j + 3] = i + 1; tris [j + 4] = i + 3; tris [j + 5] = i + 2; } Vector2[] uv = new Vector2[vs.Length]; //Set up some basic UV for (int i = 0; i < uv.Length; i += 4) { uv [i] = new Vector2(0, 0); uv [i + 1] = new Vector2(1, 0); uv [i + 2] = new Vector2(0, 1); uv [i + 3] = new Vector2(1, 1); } mesh.vertices = vs; mesh.triangles = tris; mesh.uv = uv; mesh.RecalculateNormals(); GameObject go = new GameObject("Mesh", typeof(MeshRenderer), typeof(MeshFilter)); MeshFilter fi = go.GetComponent <MeshFilter> (); fi.mesh = mesh; MeshRenderer re = go.GetComponent <MeshRenderer> (); re.material = SquareMat; RenderedGrid.Add(go); }
public IEnumerator DemoConstantPath() { ConstantPath constPath = ConstantPath.Construct(end.position, searchLength, null); AstarPath.StartPath(constPath); lastPath = constPath; // Wait for the path to be calculated yield return(StartCoroutine(constPath.WaitForPath())); ClearPrevious(); // The following code will build a mesh with a square for each node visited List <GraphNode> nodes = constPath.allNodes; Mesh mesh = new Mesh(); List <Vector3> verts = new List <Vector3>(); bool drawRaysInstead = false; // This will loop through the nodes from furthest away to nearest, not really necessary... but why not :D for (int i = nodes.Count - 1; i >= 0; i--) { Vector3 pos = (Vector3)nodes[i].position + pathOffset; if (verts.Count == 65000 && !drawRaysInstead) { Debug.LogError("Too many nodes, rendering a mesh would throw 65K vertex error. Using Debug.DrawRay instead for the rest of the nodes"); drawRaysInstead = true; } if (drawRaysInstead) { Debug.DrawRay(pos, Vector3.up, Color.blue); continue; } // Add vertices in a square GridGraph gg = AstarData.GetGraph(nodes[i]) as GridGraph; float scale = 1F; if (gg != null) { scale = gg.nodeSize; } verts.Add(pos + new Vector3(-0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(-0.5F, 0, 0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, 0.5F) * scale); } // Build triangles for the squares Vector3[] vs = verts.ToArray(); int[] tris = new int[(3 * vs.Length) / 2]; for (int i = 0, j = 0; i < vs.Length; j += 6, i += 4) { tris[j + 0] = i; tris[j + 1] = i + 1; tris[j + 2] = i + 2; tris[j + 3] = i + 1; tris[j + 4] = i + 3; tris[j + 5] = i + 2; } Vector2[] uv = new Vector2[vs.Length]; // Set up some basic UV for (int i = 0; i < uv.Length; i += 4) { uv[i] = new Vector2(0, 0); uv[i + 1] = new Vector2(1, 0); uv[i + 2] = new Vector2(0, 1); uv[i + 3] = new Vector2(1, 1); } mesh.vertices = vs; mesh.triangles = tris; mesh.uv = uv; mesh.RecalculateNormals(); GameObject go = new GameObject("Mesh", typeof(MeshRenderer), typeof(MeshFilter)); MeshFilter fi = go.GetComponent <MeshFilter>(); fi.mesh = mesh; MeshRenderer re = go.GetComponent <MeshRenderer>(); re.material = squareMat; lastRender.Add(go); }
public override void Apply(Path p, ModifierData source) { List <Node> path = p.path; List <Vector3> vectorPath = p.vectorPath; if (path == null || path.Count == 0 || vectorPath == null || vectorPath.Count != path.Count) { return; } //The graph index for the current nodes int currentGraphIndex = path[0].graphIndex; //First node which is in the graph currentGraphIndex int currentGraphStart = 0; List <Vector3> funnelPath = ListPool <Vector3> .Claim(); List <Vector3> left = ListPool <Vector3> .Claim(); List <Vector3> right = ListPool <Vector3> .Claim(); AstarProfiler.StartProfile("Construct Funnel"); for (int i = 0; i < path.Count; i++) { if (path[i].graphIndex != currentGraphIndex) { IFunnelGraph funnelGraph = AstarData.GetGraph(path[currentGraphStart]) as IFunnelGraph; if (funnelGraph == null) { //Debug.Log ("Funnel Graph is null"); for (int j = currentGraphStart; j <= i; j++) { funnelPath.Add((Vector3)path[j].position); } } else { AstarProfiler.StartProfile("Construct Funnel Real"); ConstructFunnel(funnelGraph, vectorPath, path, currentGraphStart, i - 1, funnelPath, left, right); AstarProfiler.EndProfile(); } currentGraphIndex = path[i].graphIndex; currentGraphStart = i; } } IFunnelGraph funnelGraph2 = AstarData.GetGraph(path[currentGraphStart]) as IFunnelGraph; if (funnelGraph2 == null) { for (int j = currentGraphStart; j < path.Count - 1; j++) { funnelPath.Add((Vector3)path[j].position); } } else { AstarProfiler.StartProfile("Construct Funnel Real"); ConstructFunnel(funnelGraph2, vectorPath, path, currentGraphStart, path.Count - 1, funnelPath, left, right); AstarProfiler.EndProfile(); } AstarProfiler.EndProfile(); ListPool <Vector3> .Release(p.vectorPath); p.vectorPath = funnelPath; ListPool <Vector3> .Release(left); ListPool <Vector3> .Release(right); }
/** Applies constrained movement from \a startPos to \a endPos. * The result is stored in \a clampedPos. * Returns the new current node */ public GraphNode ClampAlongNavmesh(Vector3 startPos, GraphNode _startNode, Vector3 endPos, out Vector3 clampedPos) { ConvexMeshNode startNode = (ConvexMeshNode)_startNode; clampedPos = endPos; Stack <ConvexMeshNode> stack = tmpStack; // Tiny stack List <ConvexMeshNode> closed = tmpClosed; // Tiny closed list stack.Clear(); closed.Clear(); Vector3 bestPos, p; float bestDist = float.PositiveInfinity; float d; ConvexMeshNode bestRef = null; // Search constraint Vector3 searchPos = (startPos + endPos) / 2; float searchRadius = Mathfx.MagnitudeXZ(startPos, endPos) / 2; // Init bestPos = startPos; stack.Push(startNode); closed.Add(startNode); // Self ref, start maker. INavmesh graph = AstarData.GetGraph(startNode) as INavmesh; if (graph == null) { //Debug.LogError ("Null graph, or the graph was no NavMeshGraph"); return(startNode); } #if ASTARDEBUG Debug.DrawLine(startPos, endPos, Color.blue); #endif while (stack.Count > 0) { // Pop front. ConvexMeshNode cur = stack.Pop(); // If target is inside the cur, stop search. if (NavMeshGraph.ContainsPoint(cur, endPos, graph.vertices)) { #if ASTARDEBUG Debug.DrawRay(endPos, Vector3.up, Color.red); #endif bestRef = cur; bestPos = endPos; break; } // Follow edges or keep track of nearest point on blocking edge. for (int i = 0, j = 2; i < 3; j = i++) { int sp = cur.GetVertexIndex(j); int sq = cur.GetVertexIndex(i); bool blocking = true; ConvexMeshNode conn = null; for (int q = 0; q < cur.connections.Length; q++) { conn = cur.connections[q] as ConvexMeshNode; if (conn == null) { continue; } for (int i2 = 0, j2 = 2; i2 < 3; j2 = i2++) { int sp2 = conn.GetVertexIndex(j2); int sq2 = conn.GetVertexIndex(i2); if ((sp2 == sp && sq2 == sq) || (sp2 == sq && sq2 == sp)) { blocking = false; break; } } if (!blocking) { break; } } //Node neiRef = cur->nei[j]; if (blocking) { // Blocked edge, calc distance. p = Mathfx.NearestPointStrictXZ((Vector3)graph.vertices[sp], (Vector3)graph.vertices[sq], endPos); #if ASTARDEBUG Debug.DrawLine((Vector3)graph.vertices[sp] + Vector3.up * 0.1F, (Vector3)graph.vertices[sq] + Vector3.up * 0.1F, Color.black); #endif d = Mathfx.MagnitudeXZ(p, endPos); if (d < bestDist) { // Update nearest distance. bestPos = p; bestDist = d; bestRef = cur; } } else { // Skip already visited. if (closed.Contains(conn)) { continue; } // Store to closed with parent for trace back. closed.Add(conn); #if ASTARDEBUG Debug.DrawLine((Vector3)cur.position, (Vector3)conn.position, Color.black); Debug.DrawLine((Vector3)graph.vertices[sp] + Vector3.up * 0.1F, (Vector3)graph.vertices[sq] + Vector3.up * 0.1F, Color.blue); #endif // Non-blocked edge, follow if within search radius. p = Mathfx.NearestPointStrictXZ((Vector3)graph.vertices[sp], (Vector3)graph.vertices[sq], searchPos); d = Mathfx.MagnitudeXZ(p, searchPos); if (d <= searchRadius) { #if ASTARDEBUG Debug.DrawLine((Vector3)searchPos - Vector3.up * 0.1F, p - Vector3.up * 0.1F, Color.cyan); #endif stack.Push(conn); } #if ASTARDEBUG else { Debug.DrawLine((Vector3)searchPos - Vector3.up * 0.1F, p - Vector3.up * 0.1F, Color.red); } #endif } } } // Trace back and store visited curgons. /* followVisited(bestRef,visited,closed); * // Store best movement position.*/ clampedPos = bestPos; // Return number of visited curs. return(bestRef); //visited.size(); }
/** Get the path back */ public void OnPathComplete(Path p) { //To prevent it from creating new GameObjects when the application is quitting when using multithreading. if (lastRender == null) { return; } if (p.error) { ClearPrevious(); return; } if (p.GetType() == typeof(MultiTargetPath)) { List <GameObject> unused = new List <GameObject> (lastRender); lastRender.Clear(); MultiTargetPath mp = p as MultiTargetPath; for (int i = 0; i < mp.vectorPaths.Length; i++) { if (mp.vectorPaths[i] == null) { continue; } List <Vector3> vpath = mp.vectorPaths[i]; GameObject ob = null; if (unused.Count > i && unused[i].GetComponent <LineRenderer>() != null) { ob = unused[i]; unused.RemoveAt(i); } else { ob = new GameObject("LineRenderer_" + i, typeof(LineRenderer)); } LineRenderer lr = ob.GetComponent <LineRenderer>(); lr.sharedMaterial = lineMat; lr.SetWidth(lineWidth, lineWidth); lr.SetVertexCount(vpath.Count); for (int j = 0; j < vpath.Count; j++) { lr.SetPosition(j, vpath[j] + pathOffset); } lastRender.Add(ob); } for (int i = 0; i < unused.Count; i++) { Destroy(unused[i]); } } else if (p.GetType() == typeof(ConstantPath)) { ClearPrevious(); //The following code will build a mesh with a square for each node visited ConstantPath constPath = p as ConstantPath; List <GraphNode> nodes = constPath.allNodes; Mesh mesh = new Mesh(); List <Vector3> verts = new List <Vector3>(); bool drawRaysInstead = false; // Just some debugging code which selects random points on the nodes /*List<Vector3> pts = Pathfinding.PathUtilities.GetPointsOnNodes (nodes, 20, 0); * Vector3 avg = Vector3.zero; * for (int i=0;i<pts.Count;i++) { * Debug.DrawRay (pts[i], Vector3.up*5, Color.red, 3); * avg += pts[i]; * } * * if (pts.Count > 0) avg /= pts.Count; * * for (int i=0;i<pts.Count;i++) { * pts[i] -= avg; * } * * Pathfinding.PathUtilities.GetPointsAroundPoint (start.position, AstarPath.active.astarData.graphs[0] as IRaycastableGraph, pts, 0, 1); * * for (int i=0;i<pts.Count;i++) { * Debug.DrawRay (pts[i], Vector3.up*5, Color.blue, 3); * }*/ //This will loop through the nodes from furthest away to nearest, not really necessary... but why not :D //Note that the reverse does not, as common sense would suggest, loop through from the closest to the furthest away //since is might contain duplicates and only the node duplicate placed at the highest index is guarenteed to be ordered correctly. for (int i = nodes.Count - 1; i >= 0; i--) { Vector3 pos = (Vector3)nodes[i].position + pathOffset; if (verts.Count == 65000 && !drawRaysInstead) { Debug.LogError("Too many nodes, rendering a mesh would throw 65K vertex error. Using Debug.DrawRay instead for the rest of the nodes"); drawRaysInstead = true; } if (drawRaysInstead) { Debug.DrawRay(pos, Vector3.up, Color.blue); continue; } //Add vertices in a square GridGraph gg = AstarData.GetGraph(nodes[i]) as GridGraph; float scale = 1F; if (gg != null) { scale = gg.nodeSize; } verts.Add(pos + new Vector3(-0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, -0.5F) * scale); verts.Add(pos + new Vector3(-0.5F, 0, 0.5F) * scale); verts.Add(pos + new Vector3(0.5F, 0, 0.5F) * scale); } //Build triangles for the squares Vector3[] vs = verts.ToArray(); int[] tris = new int[(3 * vs.Length) / 2]; for (int i = 0, j = 0; i < vs.Length; j += 6, i += 4) { tris[j + 0] = i; tris[j + 1] = i + 1; tris[j + 2] = i + 2; tris[j + 3] = i + 1; tris[j + 4] = i + 3; tris[j + 5] = i + 2; } Vector2[] uv = new Vector2[vs.Length]; //Set up some basic UV for (int i = 0; i < uv.Length; i += 4) { uv[i] = new Vector2(0, 0); uv[i + 1] = new Vector2(1, 0); uv[i + 2] = new Vector2(0, 1); uv[i + 3] = new Vector2(1, 1); } mesh.vertices = vs; mesh.triangles = tris; mesh.uv = uv; mesh.RecalculateNormals(); GameObject go = new GameObject("Mesh", typeof(MeshRenderer), typeof(MeshFilter)); MeshFilter fi = go.GetComponent <MeshFilter>(); fi.mesh = mesh; MeshRenderer re = go.GetComponent <MeshRenderer>(); re.material = squareMat; lastRender.Add(go); } else { ClearPrevious(); GameObject ob = new GameObject("LineRenderer", typeof(LineRenderer)); LineRenderer lr = ob.GetComponent <LineRenderer>(); lr.sharedMaterial = lineMat; lr.SetWidth(lineWidth, lineWidth); lr.SetVertexCount(p.vectorPath.Count); for (int i = 0; i < p.vectorPath.Count; i++) { lr.SetPosition(i, p.vectorPath[i] + pathOffset); } lastRender.Add(ob); } }
// Token: 0x0600001A RID: 26 RVA: 0x00002B84 File Offset: 0x00000F84 public GraphNode ClampAlongNavmesh(Vector3 startPos, GraphNode _startNode, Vector3 endPos, out Vector3 clampedPos) { TriangleMeshNode triangleMeshNode = (TriangleMeshNode)_startNode; clampedPos = endPos; Stack <TriangleMeshNode> stack = this.tmpStack; List <TriangleMeshNode> list = this.tmpClosed; stack.Clear(); list.Clear(); float num = float.PositiveInfinity; TriangleMeshNode result = null; Vector3 vector = (startPos + endPos) / 2f; float num2 = AstarMath.MagnitudeXZ(startPos, endPos) / 2f; Vector3 vector2 = startPos; stack.Push(triangleMeshNode); list.Add(triangleMeshNode); INavmesh navmesh = AstarData.GetGraph(triangleMeshNode) as INavmesh; if (navmesh == null) { return(triangleMeshNode); } while (stack.Count > 0) { TriangleMeshNode triangleMeshNode2 = stack.Pop(); int tileIndex = ((RecastGraph)navmesh).GetTileIndex(triangleMeshNode2.GetVertexIndex(0)); Int3[] verts = ((RecastGraph)navmesh).GetTiles()[tileIndex].verts; int vertexArrayIndex = triangleMeshNode2.GetVertexArrayIndex(triangleMeshNode2.v0); int vertexArrayIndex2 = triangleMeshNode2.GetVertexArrayIndex(triangleMeshNode2.v1); int vertexArrayIndex3 = triangleMeshNode2.GetVertexArrayIndex(triangleMeshNode2.v2); if (NavMeshGraph.ContainsPoint(vertexArrayIndex, vertexArrayIndex2, vertexArrayIndex3, endPos, verts)) { result = triangleMeshNode2; vector2 = endPos; break; } int i = 0; int i2 = 2; while (i < 3) { int vertexIndex = triangleMeshNode2.GetVertexIndex(i2); int vertexIndex2 = triangleMeshNode2.GetVertexIndex(i); bool flag = true; TriangleMeshNode triangleMeshNode3 = null; for (int j = 0; j < triangleMeshNode2.connections.Length; j++) { triangleMeshNode3 = (triangleMeshNode2.connections[j] as TriangleMeshNode); if (triangleMeshNode3 != null) { int k = 0; int i3 = 2; while (k < 3) { int vertexIndex3 = triangleMeshNode3.GetVertexIndex(i3); int vertexIndex4 = triangleMeshNode3.GetVertexIndex(k); if ((vertexIndex3 == vertexIndex && vertexIndex4 == vertexIndex2) || (vertexIndex3 == vertexIndex2 && vertexIndex4 == vertexIndex)) { flag = false; break; } i3 = k++; } if (!flag) { break; } } } if (flag) { Vector3 vector3 = AstarMath.NearestPointStrictXZ((Vector3)verts[vertexIndex], (Vector3)verts[vertexIndex2], endPos); float num3 = AstarMath.MagnitudeXZ(vector3, endPos); if (num3 < num) { vector2 = vector3; num = num3; result = triangleMeshNode2; } } else if (!list.Contains(triangleMeshNode3)) { list.Add(triangleMeshNode3); Vector3 vector3 = AstarMath.NearestPointStrictXZ((Vector3)verts[vertexIndex], (Vector3)verts[vertexIndex2], vector); float num3 = AstarMath.MagnitudeXZ(vector3, vector); if (num3 <= num2) { stack.Push(triangleMeshNode3); } } i2 = i++; } } clampedPos = vector2; return(result); }
public void OnPathComplete(Path p) { if (this.lastRender == null) { return; } if (p.error) { this.ClearPrevious(); return; } if (p.GetType() == typeof(MultiTargetPath)) { List <GameObject> list = new List <GameObject>(this.lastRender); this.lastRender.Clear(); MultiTargetPath multiTargetPath = p as MultiTargetPath; for (int i = 0; i < multiTargetPath.vectorPaths.Length; i++) { if (multiTargetPath.vectorPaths[i] != null) { List <Vector3> list2 = multiTargetPath.vectorPaths[i]; GameObject gameObject; if (list.Count > i && list[i].GetComponent <LineRenderer>() != null) { gameObject = list[i]; list.RemoveAt(i); } else { gameObject = new GameObject("LineRenderer_" + i, new Type[] { typeof(LineRenderer) }); } LineRenderer component = gameObject.GetComponent <LineRenderer>(); component.sharedMaterial = this.lineMat; for (int j = 0; j < list2.Count; j++) { component.SetPosition(j, list2[j] + this.pathOffset); } this.lastRender.Add(gameObject); } } for (int k = 0; k < list.Count; k++) { Object.Destroy(list[k]); } } else if (p.GetType() == typeof(ConstantPath)) { this.ClearPrevious(); ConstantPath constantPath = p as ConstantPath; List <GraphNode> allNodes = constantPath.allNodes; Mesh mesh = new Mesh(); List <Vector3> list3 = new List <Vector3>(); bool flag = false; for (int l = allNodes.Count - 1; l >= 0; l--) { Vector3 vector = (Vector3)allNodes[l].position + this.pathOffset; if (list3.Count == 65000 && !flag) { Debug.LogError("Too many nodes, rendering a mesh would throw 65K vertex error. Using Debug.DrawRay instead for the rest of the nodes"); flag = true; } if (flag) { Debug.DrawRay(vector, Vector3.up, Color.blue); } else { GridGraph gridGraph = AstarData.GetGraph(allNodes[l]) as GridGraph; float num = 1f; if (gridGraph != null) { num = gridGraph.nodeSize; } list3.Add(vector + new Vector3(-0.5f, 0f, -0.5f) * num); list3.Add(vector + new Vector3(0.5f, 0f, -0.5f) * num); list3.Add(vector + new Vector3(-0.5f, 0f, 0.5f) * num); list3.Add(vector + new Vector3(0.5f, 0f, 0.5f) * num); } } Vector3[] array = list3.ToArray(); int[] array2 = new int[3 * array.Length / 2]; int m = 0; int num2 = 0; while (m < array.Length) { array2[num2] = m; array2[num2 + 1] = m + 1; array2[num2 + 2] = m + 2; array2[num2 + 3] = m + 1; array2[num2 + 4] = m + 3; array2[num2 + 5] = m + 2; num2 += 6; m += 4; } Vector2[] array3 = new Vector2[array.Length]; for (int n = 0; n < array3.Length; n += 4) { array3[n] = new Vector2(0f, 0f); array3[n + 1] = new Vector2(1f, 0f); array3[n + 2] = new Vector2(0f, 1f); array3[n + 3] = new Vector2(1f, 1f); } mesh.vertices = array; mesh.triangles = array2; mesh.uv = array3; mesh.RecalculateNormals(); GameObject gameObject2 = new GameObject("Mesh", new Type[] { typeof(MeshRenderer), typeof(MeshFilter) }); MeshFilter component2 = gameObject2.GetComponent <MeshFilter>(); component2.mesh = mesh; MeshRenderer component3 = gameObject2.GetComponent <MeshRenderer>(); component3.material = this.squareMat; this.lastRender.Add(gameObject2); } else { this.ClearPrevious(); GameObject gameObject3 = new GameObject("LineRenderer", new Type[] { typeof(LineRenderer) }); LineRenderer component4 = gameObject3.GetComponent <LineRenderer>(); component4.sharedMaterial = this.lineMat; for (int num3 = 0; num3 < p.vectorPath.Count; num3++) { component4.SetPosition(num3, p.vectorPath[num3] + this.pathOffset); } this.lastRender.Add(gameObject3); } }
public static Vector3 GetNextTarget(Path path, Vector3 currPosition, float offset, float pickNextWaypointMargin) { if (path.error) { return(currPosition); } Int3 currentPosition = (Int3)currPosition; int startIndex = 0; int endIndex = path.path.Length; //Int3 pos = (Int3)currentPosition; //int minDist = -1; //int minNode = -1; INavmesh navmeshGraph = AstarData.GetGraph(path.path[0]) as INavmesh; if (navmeshGraph == null) { Debug.LogError("Couldn't cast graph to the appropriate type (graph isn't a Navmesh type graph, it doesn't implement the INavmesh interface)"); return(currPosition); ///Apply (path,start,end, startIndex, endIndex, graph); } Int3[] vertices = navmeshGraph.vertices; //float minDist2 = -1; //int minNode2 = -1; //Debug.Log (meshPath.Length + " "+path.Length +" "+startIndex+" "+endIndex); /*for (int i=startIndex;i< endIndex;i++) { * MeshNode node = path.path[i] as MeshNode; * * if (node == null) { * Debug.LogWarning ("Path could not be casted to Mesh Nodes"); * return currentPosition;//return base.Apply (path,start,end, startIndex, endIndex, graph); * } * * //if (Polygon.TriangleArea2 (vertices[node.v1],vertices[node.v2],currentPosition) >= 0 || Polygon.TriangleArea2 (vertices[node.v2],vertices[node.v3],currentPosition) >= 0 || Polygon.TriangleArea2 (vertices[node.v3],vertices[node.v1],currentPosition) >= 0) { * * if (!Polygon.IsClockwise (vertices[node.v1],vertices[node.v2],pos) || !Polygon.IsClockwise (vertices[node.v2],vertices[node.v3],pos) || !Polygon.IsClockwise (vertices[node.v3],vertices[node.v1],pos)) { * * if (minDist == -1) { * float dist2 = (node.position-pos).sqrMagnitude; * if (minDist2 == -1 || dist2 < minDist2) { * minDist2 = dist2; * minNode2 = i; * } * } * continue; * } * * Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.blue); * Debug.DrawLine (vertices[node.v2],vertices[node.v3],Color.blue); * Debug.DrawLine (vertices[node.v3],vertices[node.v1],Color.blue); * * * int dist = node.position.y-pos.y; * * if (minDist == -1 || dist < minDist) { * minDist = dist; * minNode = i; * } * * }*/ MeshNode lastNode = path.path[endIndex - 1] as MeshNode; if (lastNode == null) { Debug.LogWarning("Path could not be casted to Mesh Nodes"); return(currentPosition); //return base.Apply (path,start,end, startIndex, endIndex, graph); } PathNNConstraint constraint = PathNNConstraint.Default; constraint.SetStart(lastNode); NNInfo nninfo = NavMeshGraph.GetNearestForce(path.path, vertices, currPosition, constraint); currentPosition = nninfo.clampedPosition; /*for (int i=startIndex;i< endIndex;i++) { * if (nninfo.node == path.path[i]) { * minNode = i; * } * }*/ //Node minNode = nninfo.node; /*startIndex = minNode; * if (startIndex == -1) { * startIndex = minNode2; * currentPosition = path.path[minNode2].position; * } * if (startIndex == -1) { * Debug.Log ("Couldn't find current node"); * return currentPosition; * }*/ MeshNode[] meshPath = new MeshNode[endIndex - startIndex]; for (int i = startIndex; i < endIndex; i++) { meshPath[i - startIndex] = path.path[i] as MeshNode; } //return Vector3.zero; //Vector3[] vertices = null; if (leftFunnel == null || leftFunnel.Length < meshPath.Length + 1) { leftFunnel = new Int3[meshPath.Length + 1]; } if (rightFunnel == null || rightFunnel.Length < meshPath.Length + 1) { rightFunnel = new Int3[meshPath.Length + 1]; } int leftFunnelLength = meshPath.Length + 1; //int rightFunnelLength = meshPath.Length+1; leftFunnel[0] = currentPosition; rightFunnel[0] = currentPosition; leftFunnel[meshPath.Length] = path.endPoint; rightFunnel[meshPath.Length] = path.endPoint; int lastLeftIndex = -1; int lastRightIndex = -1; for (int i = 0; i < meshPath.Length - 1; i++) { //Find the connection between the nodes MeshNode n1 = meshPath[i]; MeshNode n2 = meshPath[i + 1]; bool foundFirst = false; int first = -1; int second = -1; for (int x = 0; x < 3; x++) { //Vector3 vertice1 = vertices[n1.vertices[x]]; //n1[x] gets the vertice index for vertex number 'x' in the node. Equal to n1.GetVertexIndex (x) int vertice1 = n1[x]; for (int y = 0; y < 3; y++) { //Vector3 vertice2 = vertices[n2.vertices[y]]; int vertice2 = n2[y]; if (vertice1 == vertice2) { if (foundFirst) { second = vertice2; break; } else { first = vertice2; foundFirst = true; } } } } //Debug.DrawLine ((Vector3)vertices[first]+Vector3.up*0.1F,(Vector3)vertices[second]+Vector3.up*0.1F,Color.cyan); //Debug.Log (first+" "+second); if (first == lastLeftIndex) { leftFunnel[i + 1] = vertices[first]; rightFunnel[i + 1] = vertices[second]; lastLeftIndex = first; lastRightIndex = second; } else if (first == lastRightIndex) { leftFunnel[i + 1] = vertices[second]; rightFunnel[i + 1] = vertices[first]; lastLeftIndex = second; lastRightIndex = first; } else if (second == lastLeftIndex) { leftFunnel[i + 1] = vertices[second]; rightFunnel[i + 1] = vertices[first]; lastLeftIndex = second; lastRightIndex = first; } else { leftFunnel[i + 1] = vertices[first]; rightFunnel[i + 1] = vertices[second]; lastLeftIndex = first; lastRightIndex = second; } } //Switch the arrays so the right funnel really is on the right side (and vice versa) if (!Polygon.IsClockwise(currentPosition, leftFunnel[1], rightFunnel[1])) { Int3[] tmp = leftFunnel; leftFunnel = rightFunnel; rightFunnel = tmp; } for (int i = 1; i < leftFunnelLength - 1; i++) { //float unitWidth = 2; Int3 normal = (rightFunnel[i] - leftFunnel[i]); float magn = normal.worldMagnitude; normal /= magn; normal *= Mathf.Clamp(offset, 0, (magn / 2F)); leftFunnel[i] += normal; rightFunnel[i] -= normal; //Debug.DrawLine (rightFunnel[i],leftFunnel[i],Color.blue); } /*for (int i=0;i<path.Length-1;i++) { * Debug.DrawLine (path[i].position,path[i+1].position,Color.blue); * }*/ /*for (int i=0;i<leftFunnel.Length-1;i++) { * Debug.DrawLine (leftFunnel[i],leftFunnel[i+1],Color.red); * Debug.DrawLine (rightFunnel[i],rightFunnel[i+1],Color.magenta); * }*/ if (tmpList == null) { tmpList = new List <Vector3>(3); } List <Vector3> funnelPath = tmpList; funnelPath.Clear(); funnelPath.Add(currentPosition); Int3 portalApex = currentPosition; Int3 portalLeft = leftFunnel[0]; Int3 portalRight = rightFunnel[0]; int apexIndex = 0; int rightIndex = 0; int leftIndex = 0; //yield return 0; for (int i = 1; i < leftFunnelLength; i++) { Int3 left = leftFunnel[i]; Int3 right = rightFunnel[i]; /*Debug.DrawLine (portalApex,portalLeft,Color.red); * Debug.DrawLine (portalApex,portalRight,Color.yellow); * Debug.DrawLine (portalApex,left,Color.cyan); * Debug.DrawLine (portalApex,right,Color.cyan);*/ if (Polygon.TriangleArea2(portalApex, portalRight, right) >= 0) { if (portalApex == portalRight || Polygon.TriangleArea2(portalApex, portalLeft, right) <= 0) { portalRight = right; rightIndex = i; } else { funnelPath.Add((Vector3)portalLeft); //if (funnelPath.Count > 3) //break; portalApex = portalLeft; apexIndex = leftIndex; portalLeft = portalApex; portalRight = portalApex; leftIndex = apexIndex; rightIndex = apexIndex; i = apexIndex; //yield return 0; continue; } } if (Polygon.TriangleArea2(portalApex, portalLeft, left) <= 0) { if (portalApex == portalLeft || Polygon.TriangleArea2(portalApex, portalRight, left) >= 0) { portalLeft = left; leftIndex = i; } else { funnelPath.Add((Vector3)portalRight); //if (funnelPath.Count > 3) //break; portalApex = portalRight; apexIndex = rightIndex; portalLeft = portalApex; portalRight = portalApex; leftIndex = apexIndex; rightIndex = apexIndex; i = apexIndex; //yield return 0; continue; } } //yield return 0; } //yield return 0; funnelPath.Add(path.endPoint); Vector3[] p = funnelPath.ToArray(); if (p.Length <= 1) { return(currentPosition); } for (int i = 1; i < p.Length - 1; i++) { Vector3 closest = Mathfx.NearestPointStrict(p[i], p[i + 1], currentPosition); if ((closest - (Vector3)currentPosition).sqrMagnitude < pickNextWaypointMargin * pickNextWaypointMargin) { continue; } else { return(p[i]); } } return(p[p.Length - 1]); }
// Token: 0x060029EE RID: 10734 RVA: 0x001C234B File Offset: 0x001C054B public IEnumerator DemoConstantPath() { ConstantPath constPath = ConstantPath.Construct(this.end.position, this.searchLength, null); AstarPath.StartPath(constPath, false); this.lastPath = constPath; yield return(base.StartCoroutine(constPath.WaitForPath())); this.ClearPrevious(); List <GraphNode> allNodes = constPath.allNodes; Mesh mesh = new Mesh(); List <Vector3> list = new List <Vector3>(); bool flag = false; for (int i = allNodes.Count - 1; i >= 0; i--) { Vector3 a = (Vector3)allNodes[i].position + this.pathOffset; if (list.Count == 65000 && !flag) { Debug.LogError("Too many nodes, rendering a mesh would throw 65K vertex error. Using Debug.DrawRay instead for the rest of the nodes"); flag = true; } if (flag) { Debug.DrawRay(a, Vector3.up, Color.blue); } else { GridGraph gridGraph = AstarData.GetGraph(allNodes[i]) as GridGraph; float d = 1f; if (gridGraph != null) { d = gridGraph.nodeSize; } list.Add(a + new Vector3(-0.5f, 0f, -0.5f) * d); list.Add(a + new Vector3(0.5f, 0f, -0.5f) * d); list.Add(a + new Vector3(-0.5f, 0f, 0.5f) * d); list.Add(a + new Vector3(0.5f, 0f, 0.5f) * d); } } Vector3[] array = list.ToArray(); int[] array2 = new int[3 * array.Length / 2]; int j = 0; int num = 0; while (j < array.Length) { array2[num] = j; array2[num + 1] = j + 1; array2[num + 2] = j + 2; array2[num + 3] = j + 1; array2[num + 4] = j + 3; array2[num + 5] = j + 2; num += 6; j += 4; } Vector2[] array3 = new Vector2[array.Length]; for (int k = 0; k < array3.Length; k += 4) { array3[k] = new Vector2(0f, 0f); array3[k + 1] = new Vector2(1f, 0f); array3[k + 2] = new Vector2(0f, 1f); array3[k + 3] = new Vector2(1f, 1f); } mesh.vertices = array; mesh.triangles = array2; mesh.uv = array3; mesh.RecalculateNormals(); GameObject gameObject = new GameObject("Mesh", new Type[] { typeof(MeshRenderer), typeof(MeshFilter) }); gameObject.GetComponent <MeshFilter>().mesh = mesh; gameObject.GetComponent <MeshRenderer>().material = this.squareMat; this.lastRender.Add(gameObject); yield break; }
public override void Apply(Path p, ModifierData source) { Node[] path = p.path; Vector3[] vectorPath = p.vectorPath; if (path == null || path.Length == 0 || vectorPath == null || vectorPath.Length != path.Length) { return; } //The graph index for the current nodes int currentGraphIndex = path[0].graphIndex; //First node which is in the graph currentGraphIndex int currentGraphStart = 0; List <Vector3> funnelPath = new List <Vector3> (); List <Vector3> left = new List <Vector3> (); List <Vector3> right = new List <Vector3> (); for (int i = 0; i < path.Length; i++) { if (path[i].graphIndex != currentGraphIndex) { IFunnelGraph funnelGraph = AstarData.GetGraph(path[currentGraphStart]) as IFunnelGraph; if (funnelGraph == null) { //Debug.Log ("Funnel Graph is null"); for (int j = currentGraphStart; j <= i; j++) { funnelPath.Add((Vector3)path[j].position); } } else { ConstructFunnel(funnelGraph, vectorPath, path, currentGraphStart, i - 1, funnelPath, left, right); } currentGraphIndex = path[i].graphIndex; currentGraphStart = i; } } IFunnelGraph funnelGraph2 = AstarData.GetGraph(path[currentGraphStart]) as IFunnelGraph; if (funnelGraph2 == null) { for (int j = currentGraphStart; j < path.Length - 1; j++) { funnelPath.Add((Vector3)path[j].position); } } else { ConstructFunnel(funnelGraph2, vectorPath, path, currentGraphStart, path.Length - 1, funnelPath, left, right); } p.vectorPath = funnelPath.ToArray(); }
public void OnPathRequestComplete(Path newPath) { var p = newPath as ABPath; if (p == null) { throw new Exception("This function only handles ABPaths, do not use special path types"); } _waitingForPathCalculation = false; // Increase the reference count on the new path. // This is used for object pooling to reduce allocations. p.Claim(this); // Path couldn't be calculated of some reason. // More info in p.errorLog (debug string) if (p.error) { //Debug.LogErrorFormat("Path error {0} {1} is RandomPath {2} isWander {3} end {4}",Actor.Tr.position, p.errorLog, p is RandomPath, _wandering, p.originalEndPoint); p.Release(this); _errorTimer.StartNewTime(0.5f); Stop(); return; } if (_path != null) { _path.Release(this); } _path = p; // Make sure the path contains at least 2 points if (_path.vectorPath.Count == 1) { _path.vectorPath.Add(_path.vectorPath[0]); } _interpolator.SetPath(_path); var graph = AstarData.GetGraph(_path.path[0]) as ITransformedGraph; _movementPlane = graph != null ? graph.transform : GraphTransform.identityTransform; TargetReached = false; // Simulate movement from the point where the path was requested // to where we are right now. This reduces the risk that the agent // gets confused because the first point in the path is far away // from the current position (possibly behind it which could cause // the agent to turn around, and that looks pretty bad). _interpolator.MoveToLocallyClosestPoint((Tr.position + p.originalStartPoint) * 0.5f); _interpolator.MoveToLocallyClosestPoint(Tr.position); if (Wandering) { MoveTarget = (Vector3)_path.path.LastElement().position; } if (_debugRenderer != null) { _debugRenderer.positionCount = _path.vectorPath.Count; _debugRenderer.SetPositions(_path.vectorPath.ToArray()); } var distanceToEnd = _movementPlane.ToPlane(SteeringTargetV3 - Tr.position).magnitude + _interpolator.remainingDistance; if (distanceToEnd <= _endReachedDistance) { MovementCompleted(); } }