private Stack <T> ReconstructPath(ref List <TrackerSearchNode> ClosedArray, int StartIndex, int EndIndex) { Stack <T> Path = new Stack <T>(); // init new stack TrackerSearchNode Current = null; // set current exploring node to start foreach (TrackerSearchNode node in ClosedArray) { if (StartIndex == node.Index) { Current = node; // set current to the parent of the current exploring break; } } int pointCount = 0; while (Current.Index != EndIndex) { // loop until you reached the end index pointCount++; if (pointCount != 1) { Path.Push((T)Tree[Current.Index]); // add current to the stack } foreach (TrackerSearchNode node in ClosedArray) { if (Current.Parent == node.Index) { Current = node; // set current to the parent of the current exploring break; } } } Path.Push((T)Tree[EndIndex]); // add end point. Stack <T> path = new Stack <T>(); foreach (T node in Path) { path.Push(node); } // next we reverse the stack so that it is in the correct order. return(path); // return path }
private void EscapePoint(object Data) { object[] DataArray = (object[])Data; // Convert data to data array T Position = (T)DataArray[0]; // From node Vector2 Direction = (Vector2)DataArray[1]; // Direction to look in float Distance = (float)DataArray[2]; // To node System.Action <Stack <T> > OnCalculated = (System.Action <Stack <T> >)DataArray[3]; // Convert calculated callback System.Action <string> OnError = (System.Action <string>)DataArray[4]; // Convert error callback System.Action <T> ReturnPoint = (System.Action <T>)DataArray[5]; int CurrentRegion = (int)DataArray [6]; int?LastVisitedNode = null; if (DataArray.Length >= 8) { LastVisitedNode = (int?)DataArray [7]; } int start = Tree.NodeIndex(Position); if (LastVisitedNode != null && Tree.ValidAndEnabled((int)LastVisitedNode)) { start = (int)LastVisitedNode; } else { start = Tree.GetClosedAvailable(start, (object)Tree[start], CurrentRegion); } // Initialize base data List <TrackerSearchNode> Closed = new List <TrackerSearchNode>(); // the closed array List <TrackerSearchNode> Open = new List <TrackerSearchNode>(); // the open array TrackerSearchNode InitialNode = new TrackerSearchNode(start); // the initial node to start with Vector2 StartVect = (Vector2)Tree[start]; int Goal = 0; // the holder of the int to pass when done int TickCount = 0; // tick counter int[] NeighborsCache = new int[Tree.NeighborsCount]; int MaxIt = MaxIterations; // Highest float HighestCost = 0; int HighestCostIndex = start; // Edit base data TrackerSearchNode CurrentNode = InitialNode; // creates and assigns the currentnode variable as the initial node. Open.Add(CurrentNode); // start loop while (CurrentNode.Cost < Distance && !CancelationPending && Open.Count > 0) { // tests to see if search to target is in the closed list. if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } if (TickCount > MaxIt) { break; } // check if the current iteration doesnt exceed the max iteration count if (CurrentNode.Cost >= Distance) { // checks if the current checking node is far enough away. break; // stop this void } Vector2 CurrentVect = (Vector2)Tree[CurrentNode.Index]; Tree.Neighbors(ref NeighborsCache, CurrentNode.Index); for (int i = 0; i < NeighborsCache.Length; i++) { if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } int Neighbor = NeighborsCache[i]; if (Neighbor < 0) { continue; } // continue since its not a valid neighbor if (CancelationPending) { return; } if (Neighbor < Tree.NodeCount - 1 && Neighbor > 0) // checks to make sure the neighbor is within range. { TrackerSearchNode ClosedNode = null; // get neighbor out of closed array TrackerSearchNode OpenNode = null; // get neighbor out of open array foreach (TrackerSearchNode node in Closed) { if (node.Index == Neighbor) { ClosedNode = node; break; } } foreach (TrackerSearchNode node in Open) { if (node.Index == Neighbor) { OpenNode = node; break; } } Vector2 NH = (Vector2)Tree[Neighbor]; // converts out neighbor to a vector 2 for math reasons. float difX = Mathf.Abs((NH.x - CurrentVect.x) - (Direction.x)); // x differences float difY = Mathf.Abs((NH.y - CurrentVect.y) - (Direction.y)); // y differences float dif = difX + difY; if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } float G = (int)(Tree.Cost(Neighbor, start) / 10f); // cost is distance from neighbor to start float H = dif; // sees how far off the vector directions plot line the current neighbor is. if (G > HighestCost) { HighestCost = G; HighestCostIndex = Neighbor; } // set new highest if (ClosedNode != null) { continue; } //checks to see if node exists in closed list and skips it if it is. else { // neighbor is not in closed array if (OpenNode != null) //if node is an open node. { if (OpenNode.Heuristic > H) //checks to see if the this would make for a better parent or not. { OpenNode.Cost = G; // set node cost OpenNode.Heuristic = H; } else { continue; } // else skip } else { // if node is a new node TrackerSearchNode Node = new TrackerSearchNode(Neighbor); // create new node Node.Cost = G; // set node cost Node.Heuristic = H; Open.Add(Node); // add the index to a list for iteration later } } } } if (CancelationPending) { return; } TrackerSearchNode lowest = Open[0]; //assigns a node at semi-random to be used for comparinsons to find the lowset cost node; for (int i = 0; i < Open.Count - 1; i++) // iterate through the list of open indexies. { if (lowest.Heuristic > Open[i].Heuristic) { lowest = Open[i]; } // checks this iterations open node against the assigned currentnode to see who costs less, the lowest cost one becomes the new current node } Open.Remove(CurrentNode); // removes the current node from the open indexie list as it is the lowes cost node and will soon be added to the closed list. CurrentNode = lowest; //assigns the new currentnode. Closed.Add(CurrentNode); // add current checking to the closed array if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } TickCount++; // up tickcount } if (CancelationPending) { return; } Goal = HighestCostIndex; if (ReturnPoint != null) { ReturnPoint.Invoke((T)Tree[Goal]); } else { FindPathCore(new object[] { Position, (T)Tree[Goal], OnCalculated, OnError, null, CurrentRegion, LastVisitedNode }); } }
private void FindPathCore(object Data) { // Fetching Initial data object[] DataArray = (object[])Data; // Convert data to data array T Start = (T)DataArray[0]; // From node T End = (T)DataArray[1]; // To node System.Action <Stack <T> > OnCalculated = (System.Action <Stack <T> >)DataArray[2]; // Convert calculated callback System.Action <string> OnError = (System.Action <string>)DataArray[3]; // Convert error callback System.Func <float, bool> ExitFilter = null; int CurrentRegion = -1; int?LastVisitedNode = null; if (DataArray.Length >= 5 && DataArray[4] != null) { ExitFilter = (System.Func <float, bool>)DataArray[4]; } if (DataArray.Length >= 6) { CurrentRegion = (int)DataArray[5]; } if (DataArray.Length >= 7) { LastVisitedNode = (int?)DataArray [6]; } int StartIndex = Tree.NodeIndex(Start); // find index of start node int EndIndex = Tree.NodeIndex(End); // find index of end node int[] NeighborsCache = new int[Tree.NeighborsCount]; if (LastVisitedNode != null && Tree.ValidAndEnabled((int)LastVisitedNode)) { ; StartIndex = (int)LastVisitedNode; } else { StartIndex = Tree.GetClosedAvailable(StartIndex, (object)End, CurrentRegion); } EndIndex = Tree.GetClosedAvailable(EndIndex, (object)Start, CurrentRegion); if (StartIndex > Tree.NodeCount - 1 || StartIndex < 0 || !Tree.ValidAndEnabled(StartIndex)) { if (CancelationPending) { return; } OnError.Invoke("Starting point is not part of Grid, or is not a valid walkable node"); return; } else if (EndIndex > Tree.NodeCount - 1 || EndIndex < 0 || !Tree.ValidAndEnabled(EndIndex)) { if (CancelationPending) { return; } OnError.Invoke("Desired destination is not part of Grid"); return; } // Initialize base data List <TrackerSearchNode> Open = new List <TrackerSearchNode>(); //this list will hold the acive indexies of the Open list. List <TrackerSearchNode> Closed = new List <TrackerSearchNode>(); TrackerSearchNode InitialNode = new TrackerSearchNode(EndIndex); // the initial node to start with int TickCount = 0; // tick counter Grids.GridGraph Graph = (Grids.GridGraph)Tree; // Edit base data InitialNode.Heuristic = Tree.Heuristic(StartIndex, InitialNode.Index); // calculate the heuristic of the initial node TrackerSearchNode CurrentNode = InitialNode; // creates and assigns the currentnode variable as the initial node. Open.Add(CurrentNode); // start loop while (!CancelationPending && Open.Count > 0) { // tests to see if search to target is in the closed list. if (TickCount > MaxIterations) { break; } // check if the current iteration doesnt exceed the max iteration count Closed.Add(CurrentNode); if (CurrentNode.Index == StartIndex) { // checks if the current checking node is equal to the end index Stack <T> Path = ReconstructPath(ref Closed, StartIndex, EndIndex); // Reconstruct the path if (CancelationPending) { return; } OnCalculated.Invoke(Path); // invoke the on calculated callback with the constructed path return; // stop this void } if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } Tree.Neighbors(ref NeighborsCache, CurrentNode.Index); for (int i = 0; i < NeighborsCache.Length; i++) { if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } int Neighbor = NeighborsCache[i]; if (Neighbor < 0) { continue; } // continue since its not a valid neighbor if (CancelationPending) { return; } if (Neighbor < Tree.NodeCount - 1 && Neighbor > 0 && Tree.ValidAndEnabled(CurrentNode.Index)) { TrackerSearchNode ClosedNode = null; // get neighbor out of closed array TrackerSearchNode OpenNode = null; // get neighbor out of open array foreach (TrackerSearchNode node in Closed) { if (node.Index == Neighbor) { ClosedNode = node; break; } } foreach (TrackerSearchNode node in Open) { if (node.Index == Neighbor) { OpenNode = node; break; } } float H = Tree.Heuristic(StartIndex, Neighbor); // calculate heuristic of neighbor float G = CurrentNode.Cost + 10; float F = H + G; // calculate f cost of neighbor if (ExitFilter != null && ExitFilter.Invoke(H)) { if (CancelationPending) { return; } OnError.Invoke("Cant find a path. Path is broken by exit filter!"); return; } if (ClosedNode != null) { continue; } //checks to see if node exists in closed list and skips it if it is. else { // neighbor is not in closed array if (OpenNode != null) //if node is an open node. { if (OpenNode.TotalCost > F) //checks to see if the this would make for a better parent or not. { OpenNode.Heuristic = H; // set node heuristic OpenNode.Cost = G; // set node cost OpenNode.Parent = CurrentNode.Index; //reassigns the parent } else { continue; } // else skip } else { // if node is a new node TrackerSearchNode Node = new TrackerSearchNode(Neighbor); // create new node Node.Heuristic = H; // set node heuristic Node.Cost = G; // set node cost Node.Parent = CurrentNode.Index; // set node parent Open.Add(Node); // add the index to a list for iteration later } } } } if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } if (CancelationPending) { return; } TrackerSearchNode lowest = Open[0]; //assigns a node at semi-random to be used for comparinsons to find the lowset cost node; for (int i = 0; i < Open.Count; i++) // iterate through the list of open indexies. { if (lowest.TotalCost > Open[i].TotalCost) { lowest = Open[i]; } // checks this iterations open node against the assigned currentnode to see who costs less, the lowest cost one becomes the new current node } Open.Remove(CurrentNode); // removes the current node from the open indexie list as it is the lowes cost node and will soon be added to the closed list. //Open[CurrentNode.Index] = null; // remove current checking node from the open array CurrentNode = lowest; //assigns the new currentnode. if (!Tree.ValidAndEnabled(CurrentNode.Index)) { OnError.Invoke("Obstacle interupted search"); return; } TickCount++; // up tickcount } if (CancelationPending) { return; } OnError.Invoke("No path could be found from start to end"); // something has gone wrong cause you never reached the goal node. Invoke error callback }