Advertisement
Guest User

Untitled

a guest
Dec 6th, 2016
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.45 KB | None | 0 0
  1.         /** Will calculate a number of points around \a p which are on the graph and are separated by \a clearance from each other.
  2.          * This is like GetPointsAroundPoint except that \a previousPoints are treated as being in world space.
  3.          * The average of the points will be found and then that will be treated as the group center.
  4.          *
  5.          * \param p The point to generate points around
  6.          * \param g The graph to use for linecasting. If you are only using one graph, you can get this by AstarPath.active.graphs[0] as IRaycastableGraph.
  7.          * Note that not all graphs are raycastable, recast, navmesh and grid graphs are raycastable. On recast and navmesh it works the best.
  8.          * \param previousPoints The points to use for reference. Note that these are in world space.
  9.          *      The new points will overwrite the existing points in the list. The result will be in world space.
  10.          * \param radius The final points will be at most this distance from \a p.
  11.          * \param clearanceRadius The points will if possible be at least this distance from each other.
  12.          */
  13.         public static void GetPointsAroundPointWorld (Vector3 p, IRaycastableGraph g, List<Vector3> previousPoints, float radius, float clearanceRadius) {
  14.             if (previousPoints.Count == 0) return;
  15.  
  16.             Vector3 avg = Vector3.zero;
  17.             for (int i = 0; i < previousPoints.Count; i++) avg += previousPoints[i];
  18.             avg /= previousPoints.Count;
  19.  
  20.             for (int i = 0; i < previousPoints.Count; i++) previousPoints[i] -= avg;
  21.  
  22.             GetPointsAroundPoint(p, g, previousPoints, radius, clearanceRadius);
  23.         }
  24.  
  25.         /** Will calculate a number of points around \a p which are on the graph and are separated by \a clearance from each other.
  26.          * The maximum distance from \a p to any point will be \a radius.
  27.          * Points will first be tried to be laid out as \a previousPoints and if that fails, random points will be selected.
  28.          * This is great if you want to pick a number of target points for group movement. If you pass all current agent points from e.g the group's average position
  29.          * this method will return target points so that the units move very little within the group, this is often aesthetically pleasing and reduces jitter if using
  30.          * some kind of local avoidance.
  31.          *
  32.          * \param p The point to generate points around
  33.          * \param g The graph to use for linecasting. If you are only using one graph, you can get this by AstarPath.active.graphs[0] as IRaycastableGraph.
  34.          * Note that not all graphs are raycastable, recast, navmesh and grid graphs are raycastable. On recast and navmesh it works the best.
  35.          * \param previousPoints The points to use for reference. Note that these should not be in world space. They are treated as relative to \a p.
  36.          *      The new points will overwrite the existing points in the list. The result will be in world space, not relative to \a p.
  37.          * \param radius The final points will be at most this distance from \a p.
  38.          * \param clearanceRadius The points will if possible be at least this distance from each other.
  39.          *
  40.          * \todo Write unit tests
  41.          */
  42.         public static void GetPointsAroundPoint (Vector3 p, IRaycastableGraph g, List<Vector3> previousPoints, float radius, float clearanceRadius) {
  43.             if (g == null) throw new System.ArgumentNullException("g");
  44.  
  45.             var graph = g as NavGraph;
  46.  
  47.             if (graph == null) throw new System.ArgumentException("g is not a NavGraph");
  48.  
  49.             NNInfoInternal nn = graph.GetNearestForce(p, NNConstraint.Default);
  50.             p = nn.clampedPosition;
  51.  
  52.             if (nn.node == null) {
  53.                 // No valid point to start from
  54.                 return;
  55.             }
  56.  
  57.  
  58.             // Make sure the enclosing circle has a radius which can pack circles with packing density 0.5
  59.             radius = Mathf.Max(radius, 1.4142f*clearanceRadius*Mathf.Sqrt(previousPoints.Count)); //Mathf.Sqrt(previousPoints.Count*clearanceRadius*2));
  60.             clearanceRadius *= clearanceRadius;
  61.  
  62.             for (int i = 0; i < previousPoints.Count; i++) {
  63.                 Vector3 dir = previousPoints[i];
  64.                 float magn = dir.magnitude;
  65.  
  66.                 if (magn > 0) dir /= magn;
  67.  
  68.                 float newMagn = radius;//magn > radius ? radius : magn;
  69.                 dir *= newMagn;
  70.  
  71.                 GraphHitInfo hit;
  72.  
  73.                 int tests = 0;
  74.                 while (true) {
  75.                     Vector3 pt = p + dir;
  76.  
  77.                     if (g.Linecast(p, pt, nn.node, out hit)) {
  78.                         if (hit.point == Vector3.zero) {
  79.                             // Oops, linecast actually failed completely
  80.                             // try again unless we have tried lots of times
  81.                             // then we just continue anyway
  82.                             tests++;
  83.                             if (tests > 8) {
  84.                                 previousPoints[i] = pt;
  85.                                 break;
  86.                             }
  87.                         } else {
  88.                             pt = hit.point;
  89.                         }
  90.                     }
  91.  
  92.                     bool worked = false;
  93.  
  94.                     for (float q = 0.1f; q <= 1.0f; q += 0.05f) {
  95.                         Vector3 qt = Vector3.Lerp(p, pt, q);
  96.                         worked = true;
  97.                         for (int j = 0; j < i; j++) {
  98.                             if ((previousPoints[j] - qt).sqrMagnitude < clearanceRadius) {
  99.                                 worked = false;
  100.                                 break;
  101.                             }
  102.                         }
  103.  
  104.                         // Abort after 8 tests or when we have found a valid point
  105.                         if (worked || tests > 8) {
  106.                             worked = true;
  107.                             previousPoints[i] = qt;
  108.                             break;
  109.                         }
  110.                     }
  111.  
  112.                     // Break out of nested loop
  113.                     if (worked) {
  114.                         break;
  115.                     }
  116.  
  117.                     // If we could not find a valid point, reduce the clearance radius slightly to improve
  118.                     // the chances next time
  119.                     clearanceRadius *= 0.9f;
  120.                     // This will pick points in 2D closer to the edge of the circle with a higher probability
  121.                     dir = Random.onUnitSphere * Mathf.Lerp(newMagn, radius, tests / 5);
  122.                     dir.y = 0;
  123.                     tests++;
  124.                 }
  125.             }
  126.         }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement