#if MODULE_ENTITIES
using Unity.Entities;
using Unity.Mathematics;
namespace Pathfinding.ECS {
///
/// Policy for how often to recalculate an agent's path.
///
/// See:
///
/// This is the unmanaged equivalent of .
///
[System.Serializable]
public struct AutoRepathPolicy : IComponentData {
///
/// 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:
///
public const float Sensitivity = 10.0f;
///
/// Policy to use when recalculating paths.
///
/// See: for more details.
///
public Pathfinding.AutoRepathPolicy.Mode mode;
/// Number of seconds between each automatic path recalculation for Mode.EveryNSeconds, and the maximum interval for Mode.Dynamic
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;
}
///
/// True if the path should be recalculated according to the policy
///
/// The above parameters are relevant only if is .
///
/// The current position of the agent.
/// The radius of the agent. You may pass 0.0 if the agent doesn't have a radius.
/// The goal of the agent right now
/// The current time in seconds
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;
}
/// Must be called when a path request has been scheduled
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