/// Returned by graph ray- or linecasts containing info about the hit.
/// This is the return value by the <see cref="Pathfinding.IRaycastableGraph.Linecast"/> methods.
/// Some members will also be initialized even if nothing was hit, see the individual member descriptions for more info.
///
/// [Open online documentation to see images]
/// </summary>
publicstructGraphHitInfo{
/// <summary>
/// Start of the line/ray.
/// Note that the point passed to the Linecast method will be clamped to the closest point on the navmesh.
/// </summary>
publicVector3origin;
/// <summary>
/// Hit point.
/// In case no obstacle was hit then this will be set to the endpoint of the line.
/// </summary>
publicVector3point;
/// <summary>
/// Node which contained the edge which was hit.
/// If the linecast did not hit anything then this will be set to the last node along the line's path (the one which contains the endpoint).
///
/// For layered grid graphs the linecast will return true (i.e: no free line of sight) if when walking the graph we ended up at X,Z coordinate for the end node
/// even if end node was on a different level (e.g the floor below or above in a building). In this case no node edge was really hit so this field will still be null.
/// </summary>
publicGraphNodenode;
/// <summary>
/// Where the tangent starts. <see cref="tangentOrigin"/> and <see cref="tangent"/> together actually describes the edge which was hit.
/// [Open online documentation to see images]
/// </summary>
publicVector3tangentOrigin;
/// <summary>
/// Tangent of the edge which was hit.
/// [Open online documentation to see images]
/// </summary>
publicVector3tangent;
/// <summary>Distance from <see cref="origin"/> to <see cref="point"/></summary>
publicfloatdistance{
get{
return(point-origin).magnitude;
}
}
publicGraphHitInfo(Vector3point){
tangentOrigin=Vector3.zero;
origin=Vector3.zero;
this.point=point;
node=null;
tangent=Vector3.zero;
}
}
/// <summary>Nearest node constraint. Constrains which nodes will be returned by the <see cref="AstarPath.GetNearest"/> function</summary>
publicclassNNConstraint{
/// <summary>
/// Graphs treated as valid to search on.
/// This is a bitmask meaning that bit 0 specifies whether or not the first graph in the graphs list should be able to be included in the search,
/// bit 1 specifies whether or not the second graph should be included and so on.
/// <code>
/// // Enables the first and third graphs to be included, but not the rest
/// // Find the node closest to somePoint which is either in 'My Grid Graph' OR in 'My Other Grid Graph'
/// var info = AstarPath.active.GetNearest(somePoint, nn);
/// </code>
///
/// Note: This does only affect which nodes are returned from a <see cref="AstarPath.GetNearest"/> call, if a valid graph is connected to an invalid graph using a node link then it might be searched anyway.
///
/// See: <see cref="AstarPath.GetNearest"/>
/// See: <see cref="SuitableGraph"/>
/// See: bitmasks (view in online documentation for working links)
/// </summary>
publicGraphMaskgraphMask=-1;
/// <summary>Only treat nodes in the area <see cref="area"/> as suitable. Does not affect anything if <see cref="area"/> is less than 0 (zero)</summary>
publicboolconstrainArea;
/// <summary>Area ID to constrain to. Will not affect anything if less than 0 (zero) or if <see cref="constrainArea"/> is false</summary>
publicintarea=-1;
/// <summary>Constrain the search to only walkable or unwalkable nodes depending on <see cref="walkable"/>.</summary>
publicboolconstrainWalkability=true;
/// <summary>
/// Only search for walkable or unwalkable nodes if <see cref="constrainWalkability"/> is enabled.
/// If true, only walkable nodes will be searched for, otherwise only unwalkable nodes will be searched for.
/// Does not affect anything if <see cref="constrainWalkability"/> if false.
/// </summary>
publicboolwalkable=true;
/// <summary>
/// if available, do an XZ check instead of checking on all axes.
/// The navmesh/recast graph as well as the grid/layered grid graph supports this.
///
/// This can be important on sloped surfaces. See the image below in which the closest point for each blue point is queried for:
/// [Open online documentation to see images]
///
/// The navmesh/recast graphs also contain a global option for this: <see cref="Pathfinding.NavmeshBase.nearestSearchOnlyXZ"/>.
/// </summary>
publicbooldistanceXZ;
/// <summary>
/// Sets if tags should be constrained.
/// See: <see cref="tags"/>
/// </summary>
publicboolconstrainTags=true;
/// <summary>
/// Nodes which have any of these tags set are suitable.
/// This is a bitmask, i.e bit 0 indicates that tag 0 is good, bit 3 indicates tag 3 is good etc.
/// See: <see cref="constrainTags"/>
/// See: <see cref="graphMask"/>
/// See: bitmasks (view in online documentation for working links)
/// </summary>
publicinttags=-1;
/// <summary>
/// Constrain distance to node.
/// Uses distance from <see cref="AstarPath.maxNearestNodeDistance"/>.
/// If this is false, it will completely ignore the distance limit.
///
/// If there are no suitable nodes within the distance limit then the search will terminate with a null node as a result.
/// Note: This value is not used in this class, it is used by the AstarPath.GetNearest function.
/// </summary>
publicboolconstrainDistance=true;
/// <summary>
/// Returns whether or not the graph conforms to this NNConstraint's rules.
/// Note that only the first 31 graphs are considered using this function.
/// If the <see cref="graphMask"/> has bit 31 set (i.e the last graph possible to fit in the mask), all graphs
/// above index 31 will also be considered suitable.
/// <summary>Returns a constraint which does not filter the results</summary>
publicstaticNNConstraintNone{
get{
returnnewNNConstraint{
constrainWalkability=false,
constrainArea=false,
constrainTags=false,
constrainDistance=false,
graphMask=-1,
};
}
}
/// <summary>Default constructor. Equals to the property <see cref="Default"/></summary>
publicNNConstraint(){
}
}
/// <summary>
/// A special NNConstraint which can use different logic for the start node and end node in a path.
/// A PathNNConstraint can be assigned to the Path.nnConstraint field, the path will first search for the start node, then it will call <see cref="SetStart"/> and proceed with searching for the end node (nodes in the case of a MultiTargetPath).
/// The default PathNNConstraint will constrain the end point to lie inside the same area as the start point.
/// </summary>
publicclassPathNNConstraint:NNConstraint{
publicstaticnewPathNNConstraintDefault{
get{
returnnewPathNNConstraint{
constrainArea=true
};
}
}
/// <summary>Called after the start node has been found. This is used to get different search logic for the start and end nodes in a path</summary>
publicvirtualvoidSetStart(GraphNodenode){
if(node!=null){
area=(int)node.Area;
}else{
constrainArea=false;
}
}
}
/// <summary>
/// Internal result of a nearest node query.
/// See: NNInfo
/// </summary>
publicstructNNInfoInternal{
/// <summary>
/// Closest node found.
/// This node is not necessarily accepted by any NNConstraint passed.
/// See: constrainedNode
/// </summary>
publicGraphNodenode;
/// <summary>
/// Optional to be filled in.
/// If the search will be able to find the constrained node without any extra effort it can fill it in.
/// </summary>
publicGraphNodeconstrainedNode;
/// <summary>The position clamped to the closest point on the <see cref="node"/>.</summary>
publicVector3clampedPosition;
/// <summary>Clamped position for the optional constrainedNode</summary>
publicVector3constClampedPosition;
publicNNInfoInternal(GraphNodenode){
this.node=node;
constrainedNode=null;
clampedPosition=Vector3.zero;
constClampedPosition=Vector3.zero;
UpdateInfo();
}
/// <summary>Updates <see cref="clampedPosition"/> and <see cref="constClampedPosition"/> from node positions</summary>
/// <summary>Graphs which can be updated during runtime</summary>
publicinterfaceIUpdatableGraph{
/// <summary>
/// Updates an area using the specified <see cref="GraphUpdateObject"/>.
///
/// Notes to implementators.
/// This function should (in order):
/// -# Call o.WillUpdateNode on the GUO for every node it will update, it is important that this is called BEFORE any changes are made to the nodes.
/// -# Update walkabilty using special settings such as the usePhysics flag used with the GridGraph.
/// -# Call Apply on the GUO for every node which should be updated with the GUO.
/// -# Update connectivity info if appropriate (GridGraphs updates connectivity, but most other graphs don't since then the connectivity cannot be recovered later).
/// </summary>
voidUpdateArea(GraphUpdateObjecto);
/// <summary>
/// May be called on the Unity thread before starting the update.
/// See: CanUpdateAsync
/// </summary>
voidUpdateAreaInit(GraphUpdateObjecto);
/// <summary>
/// May be called on the Unity thread after executing the update.
/// <summary>Info about if a graph update has been applied or not</summary>
publicenumGraphUpdateStage{
/// <summary>
/// The graph update object has been created, but not used for anything yet.
/// This is the default value.
/// </summary>
Created,
/// <summary>The graph update has been sent to the pathfinding system and is scheduled to be applied to the graphs</summary>
Pending,
/// <summary>The graph update has been applied to all graphs</summary>
Applied,
/// <summary>
/// The graph update has been aborted and will not be applied.
/// This can happen if the AstarPath component is destroyed while a graph update is queued to be applied.
/// </summary>
Aborted,
}
/// <summary>
/// Represents a collection of settings used to update nodes in a specific region of a graph.
/// See: AstarPath.UpdateGraphs
/// See: graph-updates (view in online documentation for working links)
/// </summary>
publicclassGraphUpdateObject{
/// <summary>
/// The bounds to update nodes within.
/// Defined in world space.
/// </summary>
publicBoundsbounds;
/// <summary>
/// Controlls if a flood fill will be carried out after this GUO has been applied.
/// Disabling this can be used to gain a performance boost, but use with care.
/// If you are sure that a GUO will not modify walkability or connections. You can set this to false.
/// For example when only updating penalty values it can save processing power when setting this to false. Especially on large graphs.
/// Note: If you set this to false, even though it does change e.g walkability, it can lead to paths returning that they failed even though there is a path,
/// or the try to search the whole graph for a path even though there is none, and will in the processes use wast amounts of processing power.
///
/// If using the basic GraphUpdateObject (not a derived class), a quick way to check if it is going to need a flood fill is to check if <see cref="modifyWalkability"/> is true or <see cref="updatePhysics"/> is true.
///
/// Deprecated: Not necessary anymore
/// </summary>
[System.Obsolete("Not necessary anymore")]
publicboolrequiresFloodFill{set{}}
/// <summary>
/// Use physics checks to update nodes.
/// When updating a grid graph and this is true, the nodes' position and walkability will be updated using physics checks
/// with settings from "Collision Testing" and "Height Testing".
///
/// When updating a PointGraph, setting this to true will make it re-evaluate all connections in the graph which passes through the <see cref="bounds"/>.
///
/// This has no effect when updating GridGraphs if <see cref="modifyWalkability"/> is turned on.
/// You should not combine <see cref="updatePhysics"/> and <see cref="modifyWalkability"/>.
///
/// On RecastGraphs, having this enabled will trigger a complete recalculation of all tiles intersecting the bounds.
/// This is quite slow (but powerful). If you only want to update e.g penalty on existing nodes, leave it disabled.
/// </summary>
publicboolupdatePhysics=true;
/// <summary>
/// Reset penalties to their initial values when updating grid graphs and <see cref="updatePhysics"/> is true.
/// If you want to keep old penalties even when you update the graph you may want to disable this option.
///
/// The images below shows two overlapping graph update objects, the right one happened to be applied before the left one. They both have updatePhysics = true and are
/// set to increase the penalty of the nodes by some amount.
///
/// The first image shows the result when resetPenaltyOnPhysics is false. Both penalties are added correctly.
/// [Open online documentation to see images]
///
/// This second image shows when resetPenaltyOnPhysics is set to true. The first GUO is applied correctly, but then the second one (the left one) is applied
/// and during its updating, it resets the penalties first and then adds penalty to the nodes. The result is that the penalties from both GUOs are not added together.
/// The green patch in at the border is there because physics recalculation (recalculation of the position of the node, checking for obstacles etc.) affects a slightly larger
/// area than the original GUO bounds because of the Grid Graph -> Collision Testing -> Diameter setting (it is enlarged by that value). So some extra nodes have their penalties reset.
///
/// [Open online documentation to see images]
/// </summary>
publicboolresetPenaltyOnPhysics=true;
/// <summary>
/// Update Erosion for GridGraphs.
/// When enabled, erosion will be recalculated for grid graphs
/// after the GUO has been applied.
///
/// In the below image you can see the different effects you can get with the different values.
/// The first image shows the graph when no GUO has been applied. The blue box is not identified as an obstacle by the graph, the reason
/// there are unwalkable nodes around it is because there is a height difference (nodes are placed on top of the box) so erosion will be applied (an erosion value of 2 is used in this graph).
/// The orange box is identified as an obstacle, so the area of unwalkable nodes around it is a bit larger since both erosion and collision has made
/// nodes unwalkable.
/// The GUO used simply sets walkability to true, i.e making all nodes walkable.
///
/// [Open online documentation to see images]
///
/// When updateErosion=True, the reason the blue box still has unwalkable nodes around it is because there is still a height difference
/// so erosion will still be applied. The orange box on the other hand has no height difference and all nodes are set to walkable.
///
/// When updateErosion=False, all nodes walkability are simply set to be walkable in this example.
///
/// See: Pathfinding.GridGraph
/// </summary>
publicboolupdateErosion=true;
/// <summary>
/// NNConstraint to use.
/// The Pathfinding.NNConstraint.SuitableGraph function will be called on the NNConstraint to enable filtering of which graphs to update.
/// Note: As the Pathfinding.NNConstraint.SuitableGraph function is A* Pathfinding Project Pro only, this variable doesn't really affect anything in the free version.
/// </summary>
publicNNConstraintnnConstraint=NNConstraint.None;
/// <summary>
/// Penalty to add to the nodes.
/// A penalty of 1000 is equivalent to the cost of moving 1 world unit.
/// </summary>
publicintaddPenalty;
/// <summary>
/// If true, all nodes' walkable variable will be set to <see cref="setWalkability"/>.
/// It is not recommended to combine this with <see cref="updatePhysics"/> since then you will just overwrite
/// what <see cref="updatePhysics"/> calculated.
/// </summary>
publicboolmodifyWalkability;
/// <summary>If <see cref="modifyWalkability"/> is true, the nodes' walkable variable will be set to this value</summary>
publicboolsetWalkability;
/// <summary>If true, all nodes' tag will be set to <see cref="setTag"/></summary>
publicboolmodifyTag;
/// <summary>If <see cref="modifyTag"/> is true, all nodes' tag will be set to this value</summary>
publicintsetTag;
/// <summary>
/// Track which nodes are changed and save backup data.
/// Used internally to revert changes if needed.
/// </summary>
publicbooltrackChangedNodes;
/// <summary>
/// Nodes which were updated by this GraphUpdateObject.
/// Will only be filled if <see cref="trackChangedNodes"/> is true.
/// Note: It might take a few frames for graph update objects to be applied.
/// If you need this info immediately, use <see cref="AstarPath.FlushGraphUpdates"/>.
/// </summary>
publicList<GraphNode>changedNodes;
privateList<uint>backupData;
privateList<Int3>backupPositionData;
/// <summary>
/// A shape can be specified if a bounds object does not give enough precision.
/// Note that if you set this, you should set the bounds so that it encloses the shape
/// because the bounds will be used as an initial fast check for which nodes that should
/// be updated.
/// </summary>
publicGraphUpdateShapeshape;
/// <summary>
/// Info about if a graph update has been applied or not.
/// Either an enum (see STAGE_CREATED and associated constants)
/// or a non-negative count of the number of graphs that are waiting to apply this graph update.
/// </summary>
internalintinternalStage=STAGE_CREATED;
internalconstintSTAGE_CREATED=-1;
internalconstintSTAGE_PENDING=-2;
internalconstintSTAGE_ABORTED=-3;
internalconstintSTAGE_APPLIED=0;
/// <summary>Info about if a graph update has been applied or not</summary>
publicGraphUpdateStagestage{
get{
switch(internalStage){
caseSTAGE_CREATED:
returnGraphUpdateStage.Created;
caseSTAGE_APPLIED:
returnGraphUpdateStage.Applied;
caseSTAGE_ABORTED:
returnGraphUpdateStage.Aborted;
// Positive numbers means it is currently being applied, so it is also pending.
default:
caseSTAGE_PENDING:
returnGraphUpdateStage.Pending;
}
}
}
/// <summary>
/// Should be called on every node which is updated with this GUO before it is updated.
/// See: <see cref="trackChangedNodes"/>
/// </summary>
/// <param name="node">The node to save fields for. If null, nothing will be done</param>
/// Reverts penalties and flags (which includes walkability) on every node which was updated using this GUO.
/// Data for reversion is only saved if <see cref="trackChangedNodes"/> is true.
///
/// Note: Not all data is saved. The saved data includes: penalties, walkability, tags, area, position and for grid graphs (not layered) it also includes connection data.
///
/// This method modifies the graph. So it must be called inside while it is safe to modify the graph, for example inside a work item as shown in the example below.
///
/// <code>
/// // Update the graph
/// var guo = new GraphUpdateObject(GetComponent<Collider>().bounds);
///
/// guo.trackChangedNodes = true;
/// AstarPath.active.UpdateGraphs(guo);
/// // Apply the update immediately
/// AstarPath.active.FlushGraphUpdates();
///
/// // Then revert the change.
/// // The reversion modifies the graph, so it must be done inside a work item
/// AstarPath.active.AddWorkItem(() => {
/// guo.RevertFromBackup();
/// });
/// // Apply the reversion immediately
/// AstarPath.active.FlushWorkItems();
/// </code>
///
/// See: blocking (view in online documentation for working links)
thrownewSystem.InvalidOperationException("Changed nodes have not been tracked, cannot revert from backup. Please set trackChangedNodes to true before applying the update.");
}
}
/// <summary>Updates the specified node using this GUO's settings</summary>
publicvirtualvoidApply(GraphNodenode){
if(shape==null||shape.Contains(node)){
//Update penalty and walkability
node.Penalty=(uint)(node.Penalty+addPenalty);
if(modifyWalkability){
node.Walkable=setWalkability;
}
//Update tags
if(modifyTag)node.Tag=(uint)setTag;
}
}
publicGraphUpdateObject(){
}
/// <summary>Creates a new GUO with the specified bounds</summary>
publicGraphUpdateObject(Boundsb){
bounds=b;
}
}
/// <summary>Graph which has a well defined transformation from graph space to world space</summary>
publicinterfaceITransformedGraph{
GraphTransformtransform{get;}
}
/// <summary>Graph which supports the Linecast method</summary>
publicinterfaceIRaycastableGraph{
/// <summary>
/// Checks if the straight line of sight between the two points on the graph is obstructed.
///
/// Returns: True if an obstacle was hit, and false otherwise.
/// </summary>
/// <param name="start">The start point of the raycast.</param>
/// <param name="end">The end point of the raycast.</param>
/// Checks if the straight line of sight between the two points on the graph is obstructed.
///
/// Returns: True if an obstacle was hit, and false otherwise.
/// </summary>
/// <param name="start">The start point of the raycast.</param>
/// <param name="end">The end point of the raycast.</param>
/// <param name="hit">Additional information about what was hit.</param>
/// <param name="trace">If you supply a list, it will be filled with all nodes that the linecast traversed. You may pass null if you don't care about this.</param>
/// <param name="filter">You may supply a callback to indicate which nodes should be considered unwalkable. Note that already unwalkable nodes cannot be made walkable in this way.</param>
if(graph==null)thrownewSystem.ArgumentException("Could not find any graph with the name '"+graphName+"'");
returnFromGraph(graph);
}
}
#regionDelegates
/// <summary>
/// Delegate with on Path object as parameter.
/// This is used for callbacks when a path has finished calculation.
/// Example function:
/// <code>
/// public void Start () {
/// // Assumes a Seeker component is attached to the GameObject
/// Seeker seeker = GetComponent<Seeker>();
///
/// // seeker.pathCallback is a OnPathDelegate, we add the function OnPathComplete to it so it will be called whenever a path has finished calculating on that seeker
/// seeker.pathCallback += OnPathComplete;
/// }
///
/// public void OnPathComplete (Path p) {
/// Debug.Log("This is called when a path is completed on the seeker attached to this GameObject");
/// 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).
/// 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.
/// <summary>What to do when the character is close to the destination</summary>
publicenumCloseToDestinationMode{
/// <summary>The character will stop as quickly as possible when within endReachedDistance (field that exist on most movement scripts) units from the destination</summary>
Stop,
/// <summary>The character will continue to the exact position of the destination</summary>
ContinueToExactDestination,
}
/// <summary>Indicates the side of a line that a point lies on</summary>
publicenumSide:byte{
/// <summary>The point lies exactly on the line</summary>
Colinear=0,
/// <summary>The point lies on the left side of the line</summary>
Left=1,
/// <summary>The point lies on the right side of the line</summary>
Right=2
}
publicenumInspectorGridHexagonNodeSize{
/// <summary>Value is the distance between two opposing sides in the hexagon</summary>
Width,
/// <summary>Value is the distance between two opposing vertices in the hexagon</summary>
Diameter,
/// <summary>Value is the raw node size of the grid</summary>
NodeSize
}
publicenumInspectorGridMode{
Grid,
IsometricGrid,
Hexagonal,
Advanced
}
/// <summary>
/// Determines which direction the agent moves in.
/// For 3D games you most likely want the ZAxisIsForward option as that is the convention for 3D games.
/// For 2D games you most likely want the YAxisIsForward option as that is the convention for 2D games.