Advertisement
Guest User

Untitled

a guest
Apr 24th, 2019
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.99 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using Pathfinding;
  4. using Pathfinding.RVO;
  5. using Pathfinding.Util;
  6. using System.Linq;
  7.  
  8. /** Starcraft 2-like avoidance.
  9.  * The main idea for this script is to
  10.  * - Reduce the local avoidance priority for agents that have reached their destination once.
  11.  * - Make agents stop if there is a high density of units around its destination.
  12.  *
  13.  * 'High density' is defined as:
  14.  * Take the circle with the center at the AI's destination and a radius such that the AI's current position
  15.  * is touching its border. Let 'A' be the area of that circle. Further let 'a' be the total area of all
  16.  * individual agents inside that circle.
  17.  * The agent should stop if a > A*0.6 or something like that. I.e if the agents inside the circle cover
  18.  * over 60% of the surface of the circle. The 60% figure can be modified.
  19.  */
  20. public class SC2Avoidance : MonoBehaviour {
  21.     IAstarAI ai;
  22.     RVOController rvo;
  23.  
  24.     [Range(0, 1)]
  25.     public float densityFraction = 0.5f;
  26.     public bool returnAfterBeingPushedAway = true;
  27.  
  28.     void Awake () {
  29.         ai = GetComponent<IAstarAI>();
  30.         rvo = GetComponent<RVOController>();
  31.     }
  32.  
  33.     float timer1 = 0;
  34.     Vector3 prevDestination;
  35.     bool reachedCurrentDestination;
  36.  
  37.     /** See https://en.wikipedia.org/wiki/Circle_packing */
  38.     const float MaximumCirclePackingDensity = 0.9069f;
  39.     static List<IAgent> agentBuffer = new List<IAgent>();
  40.  
  41.     float timer2 = 0;
  42.     bool ShouldStop () {
  43.         // If no destination has been set, then always stop
  44.         if (float.IsPositiveInfinity(ai.destination.x)) return true;
  45.  
  46.         var thisAgent = rvo.rvoAgent;
  47.         var radius = (ai.destination - ai.position).magnitude;
  48.  
  49.         var radius2 = thisAgent.Radius*5;
  50.  
  51.         if (radius > radius2) {
  52.             // If the agent is far away from the destination then do a faster check around the destination first.
  53.             if (AgentDensityInCircle(rvo.To2D(ai.destination), radius2) < MaximumCirclePackingDensity*densityFraction) return false;
  54.         }
  55.  
  56.         var result = AgentDensityInCircle(rvo.To2D(ai.destination), radius) > MaximumCirclePackingDensity*densityFraction;
  57.         //Pathfinding.Util.Draw.Debug.CircleXZ(ai.destination, radius, result ? Color.green : Color.red);
  58.  
  59.         timer2 = Mathf.Lerp(timer2, result ? 1 : 0, Time.deltaTime);
  60.         return result && timer2 > 0.1f;
  61.     }
  62.  
  63.     float AgentDensityInCircle (Vector2 position, float radius) {
  64.         agentBuffer.ClearFast();
  65.         rvo.simulator.Quadtree.FindAllTouchingCircle(position, radius, agentBuffer);
  66.         var accArea = 0f;
  67.  
  68.         // Only a single agent, never stop in that case as then the agent should just fall back
  69.         // to whatever the behaviour of the movement script is when this component is not used at all
  70.         if (agentBuffer.Count == 1) return 0f;
  71.  
  72.         for (int i = 0; i < agentBuffer.Count; i++) {
  73.             var agent = agentBuffer[i];
  74.             var distToDestination = (rvo.To2D(ai.destination) - agent.Position).magnitude;
  75.             // This will be greater than 1 if the whole agent is inside the circle with radius #radius
  76.             // and less than 0 if the whole agent is outside the circle.
  77.             // Otherwise it will be between 0 and 1.
  78.             float fractionInside = 0.5f + 0.5f*(radius - distToDestination)/agent.Radius;
  79.             if (fractionInside > 0) {
  80.                 accArea += Mathf.Min(1, fractionInside)*agent.Radius*agent.Radius*Mathf.PI;
  81.             }
  82.         }
  83.  
  84.         return accArea/(radius*radius*Mathf.PI);
  85.     }
  86.  
  87.     /** True if the agent has reached its destination.
  88.      * If the agents destination changes this will return false until a new path has been calculated.
  89.      * Note that changing the destination every frame may cause this value to never return true.
  90.      *
  91.      * True will be returned if the agent has stopped due to being close enough to the destination.
  92.      * This may be quite some distance away if there are many other agents around the destination.
  93.      *
  94.      * \see #Pathfinding.IAstarAI.destination
  95.      */
  96.     public bool reachedDestination {
  97.         get {
  98.             CheckDestination();
  99.             return reachedCurrentDestination;
  100.         }
  101.     }
  102.  
  103.     void CheckDestination () {
  104.         if (ai.destination != prevDestination) {
  105.             timer1 = float.PositiveInfinity;
  106.             reachedCurrentDestination = false;
  107.         }
  108.         prevDestination = ai.destination;
  109.     }
  110.  
  111.     void Update () {
  112.         if (rvo.locked) return;
  113.  
  114.         CheckDestination();
  115.  
  116.         if (ai.reachedEndOfPath || ShouldStop()) {
  117.             if (!ai.pathPending) {
  118.                 timer1 = 0f;
  119.                 reachedCurrentDestination = true;
  120.             }
  121.             //ai.isStopped = true;
  122.             rvo.flowFollowingStrength = Mathf.Lerp(rvo.flowFollowingStrength, 1.0f, Time.deltaTime * 1);
  123.             if (rvo.flowFollowingStrength > 0.9f) ai.isStopped = true;
  124.             rvo.priority = Mathf.Lerp(rvo.priority, 0.05f, Time.deltaTime * 2);
  125.         } else {
  126.             timer1 += Time.deltaTime;
  127.  
  128.             if (timer1 > 3) {
  129.                 if (reachedCurrentDestination) {
  130.                     if (returnAfterBeingPushedAway) {
  131.                         ai.isStopped = false;
  132.                         rvo.flowFollowingStrength = 0f;
  133.                         rvo.priority = Mathf.Lerp(rvo.priority, 0.1f, Time.deltaTime * 2);
  134.                     }
  135.                 } else {
  136.                     ai.isStopped = false;
  137.                     rvo.flowFollowingStrength = 0f;
  138.                     rvo.priority = Mathf.Lerp(rvo.priority, 0.5f, Time.deltaTime * 4);
  139.                 }
  140.             }
  141.         }
  142.     }
  143. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement