summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Pathfinding/ITraversalProvider.cs
blob: 249077b861e85901d4d2a51ed327a8bfebf78cf2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
namespace Pathfinding {
	/// <summary>
	/// Provides additional traversal information to a path request.
	///
	/// Example implementation:
	/// <code>
	/// public class MyCustomTraversalProvider : ITraversalProvider {
	///     public bool CanTraverse (Path path, GraphNode node) {
	///         // Make sure that the node is walkable and that the 'enabledTags' bitmask
	///         // includes the node's tag.
	///         return node.Walkable && (path.enabledTags >> (int)node.Tag & 0x1) != 0;
	///         // alternatively:
	///         // return DefaultITraversalProvider.CanTraverse(path, node);
	///     }
	///
	///     /** [CanTraverseDefault] */
	///     public bool CanTraverse (Path path, GraphNode from, GraphNode to) {
	///         return CanTraverse(path, to);
	///     }
	///     /** [CanTraverseDefault] */
	///
	///     public uint GetTraversalCost (Path path, GraphNode node) {
	///         // The traversal cost is the sum of the penalty of the node's tag and the node's penalty
	///         return path.GetTagPenalty((int)node.Tag) + node.Penalty;
	///         // alternatively:
	///         // return DefaultITraversalProvider.GetTraversalCost(path, node);
	///     }
	///
	///     // This can be omitted in Unity 2021.3 and newer because a default implementation (returning true) can be used there.
	///     public bool filterDiagonalGridConnections {
	///         get {
	///             return true;
	///         }
	///     }
	/// }
	/// </code>
	///
	/// See: traversal_provider (view in online documentation for working links)
	/// </summary>
	public interface ITraversalProvider {
		/// <summary>
		/// Filter diagonal connections using <see cref="GridGraph.cutCorners"/> for effects applied by this ITraversalProvider.
		/// This includes tags and other effects that this ITraversalProvider controls.
		///
		/// This only has an effect if <see cref="GridGraph.cutCorners"/> is set to false and your grid has <see cref="GridGraph.neighbours"/> set to Eight.
		///
		/// Take this example, the grid is completely walkable, but an ITraversalProvider is used to make the nodes marked with '#'
		/// as unwalkable. The agent 'S' is in the middle.
		///
		/// <code>
		/// ..........
		/// ....#.....
		/// ...<see cref="S"/>#....
		/// ....#.....
		/// ..........
		/// </code>
		///
		/// If filterDiagonalGridConnections is false the agent will be free to use the diagonal connections to move away from that spot.
		/// However, if filterDiagonalGridConnections is true (the default) then the diagonal connections will be disabled and the agent will be stuck.
		///
		/// Typically, there are a few common use cases:
		/// - If your ITraversalProvider makes walls and obstacles and you want it to behave identically to obstacles included in the original grid graph scan, then this should be true.
		/// - If your ITraversalProvider is used for agent to agent avoidance and you want them to be able to move around each other more freely, then this should be false.
		///
		/// See: <see cref="GridNode"/>
		/// </summary>
		bool filterDiagonalGridConnections => true;

		/// <summary>True if node should be able to be traversed by the path.</summary>
		bool CanTraverse(Path path, GraphNode node) => DefaultITraversalProvider.CanTraverse(path, node);

		/// <summary>
		/// True if the path can traverse a link between from and to and if to can be traversed itself.
		/// If this method returns true then a call to CanTraverse(path,to) must also return true.
		/// Thus this method is a more flexible version of <see cref="CanTraverse(Path,GraphNode)"/>.
		///
		/// If you only need the functionality for <see cref="CanTraverse(Path,GraphNode)"/> then you may implement this method by just forwarding it to <see cref="CanTraverse(Path,GraphNode)"/>
		///
		/// <code>
		/// public bool CanTraverse (Path path, GraphNode from, GraphNode to) {
		///     return CanTraverse(path, to);
		/// }
		/// </code>
		/// </summary>
		bool CanTraverse(Path path, GraphNode from, GraphNode to) => CanTraverse(path, to);

		/// <summary>
		/// Cost of traversing a given node.
		/// Should return the additional cost for traversing this node. By default if no tags or penalties
		/// are used then the traversal cost is zero. A cost of 1000 corresponds roughly to the cost of moving 1 world unit.
		/// </summary>
		uint GetTraversalCost(Path path, GraphNode node) => DefaultITraversalProvider.GetTraversalCost(path, node);
	}

	/// <summary>Convenience class to access the default implementation of the ITraversalProvider</summary>
	public static class DefaultITraversalProvider {
		public static bool CanTraverse (Path path, GraphNode node) {
			return node.Walkable && (path == null || (path.enabledTags >> (int)node.Tag & 0x1) != 0);
		}

		public static uint GetTraversalCost (Path path, GraphNode node) {
			return node.Penalty + (path != null ? path.GetTagPenalty((int)node.Tag) : 0);
		}
	}
}