private List <int> RetracePath(AbstractNode startNode, AbstractNode endNode, bool retracePath) { if (!limitPrevious) { previousAbstractNodes.Clear(); } List <int> path = new List <int>(); if (retracePath) { AbstractNode currentNode = endNode; if (!limitPrevious) { previousAbstractNodes.Add(currentNode);// visual } path.Add(currentNode.worldAreaIndex); path.Add(currentNode.sector); while (currentNode != startNode) {// if sector OR worldArea dont match, its a new one if (path[path.Count - 1] != currentNode.sector || path[path.Count - 2] != currentNode.worldAreaIndex) { path.Add(currentNode.worldAreaIndex); path.Add(currentNode.sector); } if (!limitPrevious) { previousAbstractNodes.Add(currentNode);// visual } currentNode = currentNode.parent; } if (path[path.Count - 1] != currentNode.sector) { if (!limitPrevious) { previousAbstractNodes.Add(currentNode); // visual } path.Add(currentNode.worldAreaIndex); path.Add(currentNode.sector); } } else { path.Add(0); AbstractNode currentNode = endNode; while (currentNode != startNode) { if (currentNode.connections.ContainsKey(currentNode.parent)) { path[0] += currentNode.connections[currentNode.parent]; } else { path[0] += 1; } currentNode = currentNode.parent; } } return(path); }
// find path on higher level between start and goal/destination public List <List <int> > FindPaths(Dictionary <IntVector2, Tile> startingPoints, Tile destinationTile, WorldArea destinationArea) { multiSectorNodes = new List <AbstractNode>(); int maxLevelAmount = worldData.pathfinder.maxLevelAmount; if (maxLevelAmount == 0) { if (worldData.pathfinder.worldIsMultiLayered) { Debug.Log("Invalid search: A Multi Layerd world cannot find paths with no Levels Of Abstraction "); return(null); } else { maxLevelAmount = 1; } } // adding all the start/destination nodes per level. for (int i = 0; i < maxLevelAmount; i++) { foreach (IntVector2 key in startingPoints.Keys) { Tile startTile = startingPoints[key]; startNodeSector = worldData.multiLevelSectorManager.GetSectorOfTile(i, startTile, worldData.worldAreas[key.x]); startMultiSectorNode = worldData.multiLevelSectorManager.CreateAbstractNodeInSector(startNodeSector, startTile, worldData.worldAreas[key.x]); worldData.multiLevelSectorManager.ConnectNodeInSector(startNodeSector, startMultiSectorNode, worldData.worldAreas[key.x]);//, new List<HigherNode>()); multiSectorNodes.Add(startMultiSectorNode); } // create temporary highlevel node on the start node // calculate its distance to the other high level nodes in the same sector, build connections between them destinationNodeSector = worldData.multiLevelSectorManager.GetSectorOfTile(i, destinationTile, destinationArea); destinationMultiSectorNode = worldData.multiLevelSectorManager.CreateAbstractNodeInSector(destinationNodeSector, destinationTile, destinationArea); worldData.multiLevelSectorManager.ConnectNodeInSector(destinationNodeSector, destinationMultiSectorNode, destinationArea); multiSectorNodes.Add(destinationMultiSectorNode); } bool nextStep = false; AbstractNode start; AbstractNode destination; previousNodesStartingPointCount = startingPoints.Count; sectorIndexesAllLowerPaths.Clear(); for (int j = 0; j < startingPoints.Count; j++) // for each starting point { for (int i = multiSectorNodes.Count - 1; i > -1; i -= startingPoints.Count + 1) { nextStep = false; int level = i / (startingPoints.Count + 1); start = multiSectorNodes[i - (j + 1)]; destination = multiSectorNodes[i]; if (start.sector == destination.sector)// starting point == destination { if (worldData.pathfinder.maxLevelAmount == 0) { AddToPath(new List <int> { start.worldAreaIndex, start.sector }); nextStep = true; } else { foreach (AbstractNode sectorNode in destination.connections.Keys) { if (sectorNode == start) // direct connection in sector { if (level != 0) // go to the next layer { nextStep = true; } else // level = 0, our goal is right next to us { AddToPath(new List <int> { start.worldAreaIndex, start.sector }); } break; } } } } //validSectorsFound if (!nextStep) { if (level != 0) // we have to search the path between them, using A-star on the high level network { List <int> sectorIndexes = null; if (validSectorsFound.Count == 0) { sectorIndexes = SearchHighLevelPath(start, destination, true); } else { sectorIndexes = SearchHighLevelPath(start, destination, validSectorsFound, true); } if (sectorIndexes == null) { Debug.Log("indexes ARE null, no Path on this hierachal Level: " + level); } else { validSectorsFound.Clear(); for (int k = 0; k < sectorIndexes.Count; k += 2) { foreach (int[] list in worldData.multiLevelSectorManager.GetLowerSectorsFromHigher(level, sectorIndexes[k + 1], worldData.worldAreas[sectorIndexes[k]])) { foreach (int lowerIndex in list) { validSectorsFound.Add(new IntVector2(sectorIndexes[k], lowerIndex), false); } } } } } else // lowest level reached { List <int> sectorIndexes = null; if (validSectorsFound.Count == 0) { sectorIndexes = SearchHighLevelPath(start, destination, true); } else { sectorIndexes = SearchHighLevelPath(start, destination, validSectorsFound, true); } validSectorsFound.Clear(); if (sectorIndexes != null) { AddToPath(sectorIndexes); } } } } } return(sectorIndexesAllLowerPaths); }
// cacluate distances to other high level nodes public void ConnectNodeInSector(MultiLevelSector sector, AbstractNode sectorNode, WorldArea area) { int maxNodes = sector.worldAreaNodes.Count + sector.sectorNodesOnEdge[0].Count + sector.sectorNodesOnEdge[1].Count + sector.sectorNodesOnEdge[2].Count + sector.sectorNodesOnEdge[3].Count; //Debug.Log("lowlevel sector ConnectNodeInSector " + maxNodes); // 2 sectorNodes on same location, connect them if (area.tileSectorNodeConnections[sector.level][sectorNode.tileConnection].Count > 1 && area.tileSectorNodeConnections[sector.level].ContainsKey(sectorNode.tileConnection)) { maxNodes--; manager.ConnectSectorNodes(area.tileSectorNodeConnections[sector.level][sectorNode.tileConnection][0], area.tileSectorNodeConnections[sector.level][sectorNode.tileConnection][1], 0); } openSet.Clear(); closedSet.Clear(); openSet.Add(sectorNode.tileConnection); openSet[0].integrationValue = 0; // Debug.Log("max nodes " + maxNodes); while (openSet.Count > 0 && maxNodes != 0) { Tile currentNode = openSet[0]; foreach (Tile neighbour in manager.worldData.tileManager.GetAllNeighboursForSectorNodeSearch(currentNode, area)) { //Debug.Log("neighbur"); if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); // if true, there is a higher node here if (neighbour.hasAbstractNodeConnection)//.higherLevelNodeIndex.Count > 0) { //Debug.Log("found connection"); //Get all HigherNodes on this Lower Node & connect them List <AbstractNode> neighbourSectorNodes = area.tileSectorNodeConnections[sector.level][neighbour]; // GetHigherLevelNodeList(neighbour, sector); manager.ConnectSectorNodes(sectorNode, neighbourSectorNodes, neighbour.integrationValue / 10); // 10 times scaling //more accurate but slower/ Mathf.FloorToInt((neighbour.totalPathCost / 10f) + 0.5f) maxNodes -= neighbourSectorNodes.Count; } } } closedSet.Add(currentNode); openSet.Remove(currentNode); } //Debug.Log("sectorNode connections " + sectorNode.connections.Count); // reset foreach (Tile tile in openSet) { tile.integrationValue = manager.worldData.tileManager.tileResetIntegrationValue; } foreach (Tile tile in closedSet) { tile.integrationValue = manager.worldData.tileManager.tileResetIntegrationValue; } }