#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