void Update() { Vector3 position = transform.position; Bounds loadBounds = new Bounds(position, LoadSize); Bounds unloadBounds = new Bounds(position, LoadSize * (1f + UnloadBuffer)); SECTR_Sector.GetContaining(ref loadSectors, loadBounds); SECTR_Sector.GetContaining(ref unloadSectors, unloadBounds); int sectorIndex = 0; int numSectors = sectors.Count; while (sectorIndex < numSectors) { SECTR_Sector oldSector = sectors[sectorIndex]; if (loadSectors.Contains(oldSector)) { loadSectors.Remove(oldSector); ++sectorIndex; } else if (!unloadSectors.Contains(oldSector)) { SECTR_Chunk oldChunk = oldSector.GetComponent <SECTR_Chunk>(); if (oldChunk) { oldChunk.RemoveReference(); } sectors.RemoveAt(sectorIndex); --numSectors; } else { ++sectorIndex; } } numSectors = loadSectors.Count; int layerMaskValue = LayersToLoad.value; if (numSectors > 0) { for (sectorIndex = 0; sectorIndex < numSectors; ++sectorIndex) { SECTR_Sector newSector = loadSectors[sectorIndex]; if (newSector.Frozen && ((layerMaskValue & (1 << newSector.gameObject.layer)) != 0)) { SECTR_Chunk newChunk = newSector.GetComponent <SECTR_Chunk>(); if (newChunk) { newChunk.AddReference(); } sectors.Add(newSector); } } } if (locked && Loaded) { LockSelf(false); } updated = true; }
/// Finds the shortest path through the portal graph between two points. /// The start and end points must currently be within Sector in the graph. /// <param name="path">List into which search results will be written.</param> /// <param name="start">The world space position at which to start the search.</param> /// <param name="goal">The world space goal of the search.</param> /// <param name="stopFlags">Flag set to test at each SECTR_Portal. A failed test will stop the traversal.</param> /// <returns>A list of nodes from the Start to the Goal. Empty if there is no path.</returns> public static void FindShortestPath(ref List <Node> path, Vector3 start, Vector3 goal, SECTR_Portal.PortalFlags stopFlags) { // This is an implementation of a basic A* search. // Implementation is optimized through use of a priority queue open list // and a dictionary for the closed list. path.Clear(); openSet.Clear(); closedSet.Clear(); // Get the list of starting portals, all of which will be pushed on to the open set. // There may be multiple candidate Sectors becuase the bounding boxes may overlap. SECTR_Sector.GetContaining(ref initialSectors, start); SECTR_Sector.GetContaining(ref goalSectors, goal); int numInitialSectors = initialSectors.Count; for (int initialSectorIndex = 0; initialSectorIndex < numInitialSectors; ++initialSectorIndex) { SECTR_Sector sector = initialSectors[initialSectorIndex]; if (goalSectors.Contains(sector)) { Node newElement = new Node(); newElement.Sector = sector; path.Add(newElement); return; } int numPortals = sector.Portals.Count; for (int portalIndex = 0; portalIndex < numPortals; ++portalIndex) { SECTR_Portal portal = sector.Portals[portalIndex]; if ((portal.Flags & stopFlags) == 0) { Node newElement = new Node(); newElement.Portal = portal; newElement.Sector = sector; newElement.ForwardTraversal = sector == portal.FrontSector; newElement.Cost = Vector3.Magnitude(start - portal.transform.position); float estimate = Vector3.Magnitude(goal - portal.transform.position); newElement.CostPlusEstimate = newElement.Cost + estimate; openSet.Enqueue(newElement); } } } // Time to do some A*... while (openSet.Count > 0) { Node current = openSet.Dequeue(); SECTR_Sector sector = current.ForwardTraversal ? current.Portal.BackSector : current.Portal.FrontSector; if (!sector) { continue; } // If the current element Sector contains the goal point, we're done. // NOTE: I *think* it's correct to end here but we should prove that // this is correct even strange connections of concave Sector. if (goalSectors.Contains(sector)) { Node.ReconstructPath(path, current); break; } int numPortals = sector.Portals.Count; for (int portalIndex = 0; portalIndex < numPortals; ++portalIndex) { SECTR_Portal portal = sector.Portals[portalIndex]; if (portal != current.Portal && (portal.Flags & stopFlags) == 0) { // Create a new SearchElement for this neighbor. Node neighborElement = new Node(); neighborElement.Parent = current; neighborElement.Portal = portal; neighborElement.Sector = sector; neighborElement.ForwardTraversal = sector == portal.FrontSector; neighborElement.Cost = current.Cost + Vector3.Magnitude(neighborElement.Portal.transform.position - current.Portal.transform.position); float estimate = Vector3.Magnitude(goal - neighborElement.Portal.transform.position); neighborElement.CostPlusEstimate = neighborElement.Cost + estimate; // If the closed list already contains this portal, // and that version is closer than us, we'll skip this node. Node closedElement = null; closedSet.TryGetValue(neighborElement.Portal, out closedElement); if (closedElement != null && closedElement.CostPlusEstimate < neighborElement.CostPlusEstimate) { continue; } // Check to see if the neighbor is already on the open list. Node openElement = null; for (int i = 0; i < openSet.Count; ++i) { if (openSet[i].Portal == neighborElement.Portal) { openElement = openSet[i]; break; } } // Skip this neighbor if the open neighbor is better than us. if (openElement != null && openElement.CostPlusEstimate < neighborElement.CostPlusEstimate) { continue; } // Add this neighbor to the open list. openSet.Enqueue(neighborElement); } } // Once all neighbors are considered, put this node onto the close list. if (!closedSet.ContainsKey(current.Portal)) { closedSet.Add(current.Portal, current); } } }