| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- namespace PF
- {
- /** What data to draw the graph debugging with */
- public enum GraphDebugMode {
- Areas,
- G,
- H,
- F,
- Penalty,
- Connections,
- Tags
- }
-
- /** How path results are logged by the system */
- public enum PathLog {
- /** Does not log anything. This is recommended for release since logging path results has a performance overhead. */
- None,
- /** Logs basic info about the paths */
- Normal,
- /** Includes additional info */
- Heavy,
- /** Same as heavy, but displays the info in-game using GUI */
- InGame,
- /** Same as normal, but logs only paths which returned an error */
- OnlyErrors
- }
-
- /** How to estimate the cost from to the destination.
- *
- * The heuristic is the estimated cost from the current node to the target.
- * The different heuristics have roughly the same performance except not using any heuristic at all (#None)
- * which is usually significantly slower.
- *
- * In the image below you can see a comparison of the different heuristic options for an 8-connected grid and
- * for a 4-connected grid.
- * Note that all paths within the green area will all have the same length. The only difference between the heuristics
- * is which of those paths of the same length that will be chosen.
- * Note that while the Diagonal Manhattan and Manhattan options seem to behave very differently on an 8-connected grid
- * they only do it in this case because of very small rounding errors. Usually they behave almost identically on 8-connected grids.
- *
- * \shadowimage{heuristic.png}
- *
- * Generally for a 4-connected grid graph the Manhattan option should be used as it is the true distance on a 4-connected grid.
- * For an 8-connected grid graph the Diagonal Manhattan option is the mathematically most correct option, however the Euclidean option
- * is often preferred, especially if you are simplifying the path afterwards using modifiers.
- *
- * For any graph that is not grid based the Euclidean option is the best one to use.
- *
- * \see <a href="https://en.wikipedia.org/wiki/A*_search_algorithm">Wikipedia: A* search_algorithm</a>
- */
- public enum Heuristic {
- /** Manhattan distance. \see https://en.wikipedia.org/wiki/Taxicab_geometry */
- Manhattan,
- /** Manhattan distance, but allowing diagonal movement as well.
- * \note This option is currently hard coded for the XZ plane. It will be equivalent to Manhattan distance if you try to use it in the XY plane (i.e for a 2D game).
- */
- DiagonalManhattan,
- /** Ordinary distance. \see https://en.wikipedia.org/wiki/Euclidean_distance */
- Euclidean,
- /** Use no heuristic at all.
- * This reduces the pathfinding algorithm to Dijkstra's algorithm.
- * This is usually significantly slower compared to using a heuristic, which is why the A* algorithm is usually preferred over Dijkstra's algorithm.
- * You may have to use this if you have a very non-standard graph. For example a world with a <a href="https://en.wikipedia.org/wiki/Wraparound_(video_games)">wraparound playfield</a> (think Civilization or Asteroids) and you have custom links
- * with a zero cost from one end of the map to the other end. Usually the A* algorithm wouldn't find the wraparound links because it wouldn't think to look in that direction.
- * \see https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
- */
- None
- }
-
-
-
- public static class PathFindHelper
- {
- #if !SERVER
- public static AstarPath GetConfig()
- {
- return AstarPath.active;
- }
- #else
- public static AStarConfig GetConfig()
- {
- return AStarConfig.Instance;
- }
- #endif
-
- /**
- * Returns the nearest node to a position using the specified NNConstraint.
- * Searches through all graphs for their nearest nodes to the specified position and picks the closest one.\n
- * Using the NNConstraint.None constraint.
- *
- * \snippet MiscSnippets.cs AstarPath.GetNearest1
- *
- * \see Pathfinding.NNConstraint
- */
- public static NNInfo GetNearest(Vector3 position)
- {
- return GetNearest(position, NNConstraint.None);
- }
- /**
- * Returns the nearest node to a position using the specified NNConstraint.
- * Searches through all graphs for their nearest nodes to the specified position and picks the closest one.
- * The NNConstraint can be used to specify constraints on which nodes can be chosen such as only picking walkable nodes.
- *
- * \snippet MiscSnippets.cs AstarPath.GetNearest2
- *
- * \snippet MiscSnippets.cs AstarPath.GetNearest3
- *
- * \see Pathfinding.NNConstraint
- */
- public static NNInfo GetNearest(Vector3 position, NNConstraint constraint)
- {
- return GetNearest(position, constraint, null);
- }
- /**
- * Returns the nearest node to a position using the specified NNConstraint.
- * Searches through all graphs for their nearest nodes to the specified position and picks the closest one.
- * The NNConstraint can be used to specify constraints on which nodes can be chosen such as only picking walkable nodes.
- * \see Pathfinding.NNConstraint
- */
- public static NNInfo GetNearest(Vector3 position, NNConstraint constraint, GraphNode hint)
- {
- // Cache property lookup
- var localGraphs = GetConfig().graphs;
- float minDist = float.PositiveInfinity;
- NNInfoInternal nearestNode = new NNInfoInternal();
- int nearestGraph = -1;
- if (localGraphs != null)
- {
- for (int i = 0; i < localGraphs.Length; i++)
- {
- NavGraph graph = localGraphs[i];
- // Check if this graph should be searched
- if (graph == null || !constraint.SuitableGraph(i, graph))
- {
- continue;
- }
- NNInfoInternal nnInfo;
- if (GetConfig().fullGetNearestSearch)
- {
- // Slower nearest node search
- // this will try to find a node which is suitable according to the constraint
- nnInfo = graph.GetNearestForce(position, constraint);
- }
- else
- {
- // Fast nearest node search
- // just find a node close to the position without using the constraint that much
- // (unless that comes essentially 'for free')
- nnInfo = graph.GetNearest(position, constraint);
- }
- GraphNode node = nnInfo.node;
- // No node found in this graph
- if (node == null)
- {
- continue;
- }
- // Distance to the closest point on the node from the requested position
- float dist = ((Vector3) nnInfo.clampedPosition - position).magnitude;
- if (GetConfig().prioritizeGraphs && dist < GetConfig().prioritizeGraphsLimit)
- {
- // The node is close enough, choose this graph and discard all others
- minDist = dist;
- nearestNode = nnInfo;
- nearestGraph = i;
- break;
- }
- else
- {
- // Choose the best node found so far
- if (dist < minDist)
- {
- minDist = dist;
- nearestNode = nnInfo;
- nearestGraph = i;
- }
- }
- }
- }
- // No matches found
- if (nearestGraph == -1)
- {
- return new NNInfo();
- }
- // Check if a constrained node has already been set
- if (nearestNode.constrainedNode != null)
- {
- nearestNode.node = nearestNode.constrainedNode;
- nearestNode.clampedPosition = nearestNode.constClampedPosition;
- }
- if (!GetConfig().fullGetNearestSearch && nearestNode.node != null && !constraint.Suitable(nearestNode.node))
- {
- // Otherwise, perform a check to force the graphs to check for a suitable node
- NNInfoInternal nnInfo = localGraphs[nearestGraph].GetNearestForce(position, constraint);
- if (nnInfo.node != null)
- {
- nearestNode = nnInfo;
- }
- }
- if (!constraint.Suitable(nearestNode.node) || (constraint.constrainDistance &&
- (nearestNode.clampedPosition - position).sqrMagnitude > GetConfig().maxNearestNodeDistanceSqr))
- {
- return new NNInfo();
- }
- // Convert to NNInfo which doesn't have all the internal fields
- return new NNInfo(nearestNode);
- }
- public static PathHandler debugPathData
- {
- get
- {
- return GetConfig().debugPathData;
- }
- set
- {
- GetConfig().debugPathData = value;
- }
- }
-
- public static ushort debugPathID
- {
- get
- {
- return GetConfig().debugPathID;
- }
- set
- {
- GetConfig().debugPathID = value;
- }
- }
- public static PathProcessor pathProcessor
- {
- get
- {
- return GetConfig().pathProcessor;
- }
- set
- {
- GetConfig().pathProcessor = value;
- }
- }
-
- public static bool IsUsingMultithreading {
- get {
- //return GetConfig().pathProcessor.IsUsingMultithreading;
- return false;
- }
- }
-
- public static NavGraph[] graphs
- {
- get {
- return GetConfig().graphs;
- }
- }
-
- public static Heuristic heuristic
- {
- get
- {
- return GetConfig().heuristic;
- }
- set
- {
- GetConfig().heuristic = value;
- }
- }
-
- public static float heuristicScale
- {
- get
- {
- return GetConfig().heuristicScale;
- }
- set
- {
- GetConfig().heuristicScale = value;
- }
- }
-
- public static EuclideanEmbedding euclideanEmbedding
- {
- get
- {
- return GetConfig().euclideanEmbedding;
- }
- set
- {
- GetConfig().euclideanEmbedding = value;
- }
- }
-
- public static PathLog logPathResults
- {
- get
- {
- return GetConfig().logPathResults;
- }
- set
- {
- GetConfig().logPathResults = value;
- }
- }
-
- /** Returns a new global node index.
- * \warning This method should not be called directly. It is used by the GraphNode constructor.
- */
- public static int GetNewNodeIndex () {
- return pathProcessor.GetNewNodeIndex();
- }
-
- /** Initializes temporary path data for a node.
- * \warning This method should not be called directly. It is used by the GraphNode constructor.
- */
- public static void InitializeNode (GraphNode node) {
- pathProcessor.InitializeNode(node);
- }
-
- /** @name Callbacks */
- /* Callbacks to pathfinding events.
- * These allow you to hook in to the pathfinding process.\n
- * Callbacks can be used like this:
- * \snippet MiscSnippets.cs AstarPath.Callbacks
- */
- /** @{ */
-
- /** Called on Awake before anything else is done.
- * This is called at the start of the Awake call, right after #active has been set, but this is the only thing that has been done.\n
- * Use this when you want to set up default settings for an AstarPath component created during runtime since some settings can only be changed in Awake
- * (such as multithreading related stuff)
- * \snippet MiscSnippets.cs AstarPath.OnAwakeSettings
- */
- public static System.Action OnAwakeSettings;
-
- /** Called for each path before searching. Be careful when using multithreading since this will be called from a different thread. */
- public static OnPathDelegate OnPathPreSearch;
-
- /** Called for each path after searching. Be careful when using multithreading since this will be called from a different thread. */
- public static OnPathDelegate OnPathPostSearch;
-
- /**
- * Called when \a pathID overflows 65536 and resets back to zero.
- * \note This callback will be cleared every time it is called, so if you want to register to it repeatedly, register to it directly on receiving the callback as well.
- */
- public static System.Action On65KOverflow;
-
-
- /** The next unused Path ID.
- * Incremented for every call to GetNextPathID
- */
- private static ushort nextFreePathID = 1;
- /** Returns the next free path ID */
- public static ushort GetNextPathID () {
- if (nextFreePathID == 0) {
- nextFreePathID++;
- if (On65KOverflow != null) {
- System.Action tmp = On65KOverflow;
- On65KOverflow = null;
- tmp();
- }
- }
- return nextFreePathID++;
- }
- public static void Close()
- {
- OnAwakeSettings = null;
- OnPathPreSearch = null;
- OnPathPostSearch = null;
- On65KOverflow = null;
- }
- }
- }
|