using UnityEngine; using Unity.Mathematics; using System.Collections.Generic; using Pathfinding.Pooling; namespace Pathfinding { /// /// Finds all nodes within a specified distance from the start. /// This class will search outwards from the start point and find all nodes which it costs less than to reach, this is usually the same as the distance to them multiplied with 1000. /// /// The path can be called like: /// /// // Here you create a new path and set how far it should search. /// ConstantPath cpath = ConstantPath.Construct(transform.position, 20000, null); /// AstarPath.StartPath(cpath); /// /// // Block until the path has been calculated. You can also calculate it asynchronously /// // by providing a callback in the constructor above. /// cpath.BlockUntilCalculated(); /// /// // Draw a line upwards from all nodes within range /// for (int i = 0; i < cpath.allNodes.Count; i++) { /// Debug.DrawRay((Vector3)cpath.allNodes[i].position, Vector3.up, Color.red, 2f); /// } /// /// /// When the path has been calculated, all nodes it searched will be stored in the variable (remember that you need to cast it from Path to ConstantPath first to get the variable). /// /// This list will be sorted by the cost to reach that node (more specifically the G score if you are familiar with the terminology for search algorithms). /// [Open online documentation to see images] /// public class ConstantPath : Path { public GraphNode startNode; public Vector3 startPoint; public Vector3 originalStartPoint; /// /// Contains all nodes the path found. /// This list will be sorted by G score (cost/distance to reach the node). /// public List allNodes; /// /// Determines when the path calculation should stop. /// This is set up automatically in the constructor to an instance of the Pathfinding.EndingConditionDistance class with a maxGScore is specified in the constructor. /// /// See: Pathfinding.PathEndingCondition for examples /// public PathEndingCondition endingCondition; /// /// Constructs a ConstantPath starting from the specified point. /// /// Searching will be stopped when a node has a G score (cost to reach it) greater or equal to maxGScore /// in order words it will search all nodes with a cost to get there less than maxGScore. /// /// From where the path will be started from (the closest node to that point will be used). /// Searching will be stopped when a node has a G score (cost to reach the node) greater than this. /// Will be called when the path has been calculated, leave as null if you use a Seeker component. public static ConstantPath Construct (Vector3 start, int maxGScore, OnPathDelegate callback = null) { var p = PathPool.GetPath(); p.Setup(start, maxGScore, callback); return p; } /// Sets up a ConstantPath starting from the specified point protected void Setup (Vector3 start, int maxGScore, OnPathDelegate callback) { this.callback = callback; startPoint = start; originalStartPoint = startPoint; endingCondition = new EndingConditionDistance(this, maxGScore); } protected override void OnEnterPool () { base.OnEnterPool(); if (allNodes != null) Pooling.ListPool.Release(ref allNodes); } /// /// Reset the path to default values. /// Clears the list. /// Note: This does not reset the . /// /// Also sets to Heuristic.None as it is the default value for this path type /// protected override void Reset () { base.Reset(); allNodes = Pooling.ListPool.Claim(); endingCondition = null; originalStartPoint = Vector3.zero; startPoint = Vector3.zero; startNode = null; heuristic = Heuristic.None; } protected override void Prepare () { var startNNInfo = GetNearest(startPoint); startNode = startNNInfo.node; if (startNode == null) { FailWithError("Could not find close node to the start point"); return; } pathHandler.AddTemporaryNode(new TemporaryNode { type = TemporaryNodeType.Start, position = (Int3)startNNInfo.position, associatedNode = startNode.NodeIndex, }); heuristicObjective = new HeuristicObjective(int3.zero, Heuristic.None, 0.0f); AddStartNodesToHeap(); } protected override void OnHeapExhausted () { CompleteState = PathCompleteState.Complete; } protected override void OnFoundEndNode (uint pathNode, uint hScore, uint gScore) { throw new System.InvalidOperationException("ConstantPaths do not have any end nodes"); } public override void OnVisitNode (uint pathNode, uint hScore, uint gScore) { var node = pathHandler.GetNode(pathNode); if (endingCondition.TargetFound(node, hScore, gScore)) { CompleteState = PathCompleteState.Complete; } else { allNodes.Add(node); } } } /// /// Target is found when the path is longer than a specified value. /// Actually this is defined as when the current node's G score is >= a specified amount (EndingConditionDistance.maxGScore). /// The G score is the cost from the start node to the current node, so an area with a higher penalty (weight) will add more to the G score. /// However the G score is usually just the shortest distance from the start to the current node. /// /// See: Pathfinding.ConstantPath which uses this ending condition /// public class EndingConditionDistance : PathEndingCondition { /// Max G score a node may have public int maxGScore = 100; public EndingConditionDistance (Path p, int maxGScore) : base(p) { this.maxGScore = maxGScore; } public override bool TargetFound (GraphNode node, uint H, uint G) { return (int)G >= maxGScore; } } }