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);
}
}
}
|