summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs
blob: a9324c153853435aa2697356bc81ba168db7c73c (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
#if MODULE_ENTITIES
using Unity.Entities;
using Unity.Mathematics;

namespace Pathfinding.ECS {
	/// <summary>
	/// Policy for how often to recalculate an agent's path.
	///
	/// See: <see cref="FollowerEntity.autoRepath"/>
	///
	/// This is the unmanaged equivalent of <see cref="Pathfinding.AutoRepathPolicy"/>.
	/// </summary>
	[System.Serializable]
	public struct AutoRepathPolicy : IComponentData {
		/// <summary>
		/// How sensitive the agent should be to changes in its destination for Mode.Dynamic.
		/// A higher value means the destination has to move less for the path to be recalculated.
		///
		/// See: <see cref="AutoRepathPolicy.Mode"/>
		/// </summary>
		public const float Sensitivity = 10.0f;

		/// <summary>
		/// Policy to use when recalculating paths.
		///
		/// See: <see cref="Pathfinding.AutoRepathPolicy.Mode"/> for more details.
		/// </summary>
		public Pathfinding.AutoRepathPolicy.Mode mode;

		/// <summary>Number of seconds between each automatic path recalculation for Mode.EveryNSeconds, and the maximum interval for Mode.Dynamic</summary>
		public float period;

		float3 lastDestination;
		float lastRepathTime;

		public static AutoRepathPolicy Default => new AutoRepathPolicy {
			mode = Pathfinding.AutoRepathPolicy.Mode.Dynamic,
			period = 2,
			lastDestination = float.PositiveInfinity,
			lastRepathTime = float.NegativeInfinity
		};

		public AutoRepathPolicy (Pathfinding.AutoRepathPolicy policy) {
			mode = policy.mode;
			period = policy.mode == Pathfinding.AutoRepathPolicy.Mode.Dynamic ? policy.maximumPeriod : policy.period;
			lastDestination = float.PositiveInfinity;
			lastRepathTime = float.NegativeInfinity;
		}

		/// <summary>
		/// True if the path should be recalculated according to the policy
		///
		/// The above parameters are relevant only if <see cref="mode"/> is <see cref="Mode.Dynamic"/>.
		/// </summary>
		/// <param name="position">The current position of the agent.</param>
		/// <param name="radius">The radius of the agent. You may pass 0.0 if the agent doesn't have a radius.</param>
		/// <param name="destination">The goal of the agent right now</param>
		/// <param name="time">The current time in seconds</param>
		public bool ShouldRecalculatePath (float3 position, float radius, float3 destination, float time) {
			if (mode == Pathfinding.AutoRepathPolicy.Mode.Never || float.IsPositiveInfinity(destination.x)) return false;

			float timeSinceLast = time - lastRepathTime;
			if (mode == Pathfinding.AutoRepathPolicy.Mode.EveryNSeconds) {
				return timeSinceLast >= period;
			} else {
				// cost = change in destination / max(distance to destination, radius)
				float squaredCost = math.lengthsq(destination - lastDestination) / math.max(math.lengthsq(position - lastDestination), radius*radius);
				float fraction = squaredCost * (Sensitivity*Sensitivity);
				if (float.IsNaN(fraction)) {
					// The agent's radius is zero, and the destination is precisely at the agent's position, which is also the destination of the last calculated path
					// This is a special case. It happens sometimes for the AILerp component when it reaches its
					// destination, as the AILerp component has no radius.
					// In this case we just use the maximum period.
					fraction = 0;
				}

				return timeSinceLast >= period*(1 - math.sqrt(fraction));
			}
		}

		public void Reset () {
			lastDestination = float.PositiveInfinity;
			lastRepathTime = float.NegativeInfinity;
		}

		/// <summary>Must be called when a path request has been scheduled</summary>
		public void DidRecalculatePath (float3 destination, float time) {
			lastRepathTime = time;
			lastDestination = destination;
			// Randomize the repath time slightly so that all agents don't request a path at the same time
			// in the future. This is useful when there are a lot of agents instantiated at exactly the same time.
			const float JITTER_AMOUNT = 0.3f;
			lastRepathTime -= (UnityEngine.Random.value - 0.5f) * JITTER_AMOUNT * period;
		}
	}
}
#endif