156 lines
6.0 KiB
C#
156 lines
6.0 KiB
C#
|
|
using UnityEngine;
|
|
using Unity.Mathematics;
|
|
using System.Collections.Generic;
|
|
using Pathfinding.Pooling;
|
|
|
|
namespace Pathfinding {
|
|
/// <summary>
|
|
/// 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 <see cref="EndingConditionDistance.maxGScore"/> to reach, this is usually the same as the distance to them multiplied with 1000.
|
|
///
|
|
/// The path can be called like:
|
|
/// <code>
|
|
/// // 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);
|
|
/// }
|
|
/// </code>
|
|
///
|
|
/// When the path has been calculated, all nodes it searched will be stored in the variable <see cref="ConstantPath.allNodes"/> (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]
|
|
/// </summary>
|
|
public class ConstantPath : Path {
|
|
public GraphNode startNode;
|
|
public Vector3 startPoint;
|
|
public Vector3 originalStartPoint;
|
|
|
|
/// <summary>
|
|
/// Contains all nodes the path found.
|
|
/// This list will be sorted by G score (cost/distance to reach the node).
|
|
/// </summary>
|
|
public List<GraphNode> allNodes;
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public PathEndingCondition endingCondition;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="start">From where the path will be started from (the closest node to that point will be used).</param>
|
|
/// <param name="maxGScore">Searching will be stopped when a node has a G score (cost to reach the node) greater than this.</param>
|
|
/// <param name="callback">Will be called when the path has been calculated, leave as null if you use a Seeker component.</param>
|
|
public static ConstantPath Construct (Vector3 start, int maxGScore, OnPathDelegate callback = null) {
|
|
var p = PathPool.GetPath<ConstantPath>();
|
|
|
|
p.Setup(start, maxGScore, callback);
|
|
return p;
|
|
}
|
|
|
|
/// <summary>Sets up a ConstantPath starting from the specified point</summary>
|
|
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<GraphNode>.Release(ref allNodes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset the path to default values.
|
|
/// Clears the <see cref="allNodes"/> list.
|
|
/// Note: This does not reset the <see cref="endingCondition"/>.
|
|
///
|
|
/// Also sets <see cref="heuristic"/> to Heuristic.None as it is the default value for this path type
|
|
/// </summary>
|
|
protected override void Reset () {
|
|
base.Reset();
|
|
allNodes = Pooling.ListPool<GraphNode>.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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public class EndingConditionDistance : PathEndingCondition {
|
|
/// <summary>Max G score a node may have</summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|