Advertisement
Guest User

Untitled

a guest
Nov 5th, 2017
237
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.79 KB | None | 0 0
  1. using UnityEngine;
  2.  
  3. namespace Pathfinding {
  4.     /** Attach this script to any obstacle with a collider to enable dynamic updates of the graphs around it.
  5.      * When the object has moved a certain distance (or actually when it's bounding box has changed by a certain amount) defined by #updateError
  6.      * it will call AstarPath.UpdateGraphs and update the graph around it.
  7.      *
  8.      * Make sure that any children colliders do not extend beyond the bounds of the collider attached to the
  9.      * GameObject that the DynamicGridObstacle component is attached to since this script only updates the graph
  10.      * using the bounds of the collider on the same GameObject.
  11.      *
  12.      * \note This script only works with GridGraph, PointGraph and LayerGridGraph
  13.      *
  14.      * \see AstarPath.UpdateGraphs
  15.      * \see graph-updates
  16.      */
  17.     public class DynamicGridObstacle : GraphModifier {
  18.         /** Collider to get bounds information from */
  19.         Collider coll;
  20.  
  21.         /** 2D Collider to get bounds information from */
  22.         Collider2D coll2D;
  23.  
  24.         /** Cached transform component */
  25.         Transform tr;
  26.  
  27.         /** The minimum change in world units along one of the axis of the bounding box of the collider to trigger a graph update */
  28.         public float updateError = 1;
  29.  
  30.         /** Time in seconds between bounding box checks.
  31.          * If AstarPath.batchGraphUpdates is enabled, it is not beneficial to have a checkTime much lower
  32.          * than AstarPath.graphUpdateBatchingInterval because that will just add extra unnecessary graph updates.
  33.          *
  34.          * In real time seconds (based on Time.realtimeSinceStartup).
  35.          */
  36.         public float checkTime = 0.2F;
  37.  
  38.         /** Bounds of the collider the last time the graphs were updated */
  39.         Bounds prevBounds;
  40.  
  41.         /** Rotation of the collider the last time the graphs were updated */
  42.         Quaternion prevRotation;
  43.  
  44.         /** True if the collider was enabled last time the graphs were updated */
  45.         bool prevEnabled;
  46.  
  47.         float lastCheckTime = -9999;
  48.  
  49.         Bounds bounds {
  50.             get {
  51.                 if (coll != null) {
  52.                     return coll.bounds;
  53.                 } else {
  54.                     var b = coll2D.bounds;
  55.                     // Make sure the bounding box stretches close to infinitely along the Z axis (which is the axis perpendicular to the 2D plane).
  56.                     // We don't want any change along the Z axis to make a difference.
  57.                     b.extents += new Vector3(0, 0, 10000);
  58.                     return b;
  59.                 }
  60.             }
  61.         }
  62.  
  63.         bool colliderEnabled {
  64.             get {
  65.                 return coll != null ? coll.enabled : coll2D.enabled;
  66.             }
  67.         }
  68.  
  69.         protected override void Awake () {
  70.             base.Awake();
  71.             coll = GetComponent<Collider>();
  72.             coll2D = GetComponent<Collider2D>();
  73.             tr = transform;
  74.             if (coll == null && coll2D == null) {
  75.                 throw new System.Exception("A collider or 2D collider must be attached to the GameObject(" + gameObject.name + ") for the DynamicGridObstacle to work");
  76.             }
  77.  
  78.             prevBounds = bounds;
  79.             prevRotation = tr.rotation;
  80.             // Make sure we update the graph as soon as we find that the collider is enabled
  81.             prevEnabled = false;
  82.         }
  83.  
  84.         public override void OnPostScan () {
  85.             // In case the object was in the scene from the start and the graphs
  86.             // were scanned then we ignore the first update since it is unnecessary.
  87.             prevEnabled = colliderEnabled;
  88.         }
  89.  
  90.         void Update () {
  91.             if (coll == null && coll2D == null) {
  92.                 Debug.LogError("Removed collider from DynamicGridObstacle", this);
  93.                 enabled = false;
  94.                 return;
  95.             }
  96.  
  97.             if (AstarPath.active == null || AstarPath.active.isScanning || Time.realtimeSinceStartup - lastCheckTime < checkTime || !Application.isPlaying) {
  98.                 return;
  99.             }
  100.  
  101.             lastCheckTime = Time.realtimeSinceStartup;
  102.             if (colliderEnabled) {
  103.                 // The current bounds of the collider
  104.                 Bounds newBounds = bounds;
  105.                 var newRotation = tr.rotation;
  106.  
  107.                 Vector3 minDiff = prevBounds.min - newBounds.min;
  108.                 Vector3 maxDiff = prevBounds.max - newBounds.max;
  109.  
  110.                 var extents = newBounds.extents.magnitude;
  111.                 // This is the distance that a point furthest out on the bounding box
  112.                 // would have moved due to the changed rotation of the object
  113.                 var errorFromRotation = extents*Quaternion.Angle(prevRotation, newRotation)*Mathf.Deg2Rad;
  114.  
  115.                 // If the difference between the previous bounds and the new bounds is greater than some value, update the graphs
  116.                 if (minDiff.sqrMagnitude > updateError*updateError || maxDiff.sqrMagnitude > updateError*updateError ||
  117.                     errorFromRotation > updateError || !prevEnabled) {
  118.                     // Update the graphs as soon as possible
  119.                     DoUpdateGraphs();
  120.                 }
  121.             } else {
  122.                 // Collider has just been disabled
  123.                 if (prevEnabled) {
  124.                     DoUpdateGraphs();
  125.                 }
  126.             }
  127.         }
  128.  
  129.         /** Revert graphs when disabled.
  130.          * When the DynamicObstacle is disabled or destroyed, a last graph update should be done to revert nodes to their original state
  131.          */
  132.         protected override void OnDisable () {
  133.             base.OnDisable();
  134.             if (AstarPath.active != null && Application.isPlaying) {
  135.                 var guo = new GraphUpdateObject(prevBounds);
  136.                 AstarPath.active.UpdateGraphs(guo);
  137.                 prevEnabled = false;
  138.             }
  139.         }
  140.  
  141.         /** Update the graphs around this object.
  142.          * \note The graphs will not be updated immediately since the pathfinding threads need to be paused first.
  143.          * If you want to guarantee that the graphs have been updated then call AstarPath.active.FlushGraphUpdates()
  144.          * after the call to this method.
  145.          */
  146.         public void DoUpdateGraphs () {
  147.             if (coll == null && coll2D == null) return;
  148.  
  149.             if (!colliderEnabled) {
  150.                 // If the collider is not enabled, then col.bounds will empty
  151.                 // so just update prevBounds
  152.                 AstarPath.active.UpdateGraphs(prevBounds);
  153.             } else {
  154.                 Bounds newBounds = bounds;
  155.  
  156.                 Bounds merged = newBounds;
  157.                 merged.Encapsulate(prevBounds);
  158.  
  159.                 // Check what seems to be fastest, to update the union of prevBounds and newBounds in a single request
  160.                 // or to update them separately, the smallest volume is usually the fastest
  161.                 if (BoundsVolume(merged) < BoundsVolume(newBounds) + BoundsVolume(prevBounds)) {
  162.                     // Send an update request to update the nodes inside the 'merged' volume
  163.                     AstarPath.active.UpdateGraphs(merged);
  164.                 } else {
  165.                     // Send two update request to update the nodes inside the 'prevBounds' and 'newBounds' volumes
  166.                     AstarPath.active.UpdateGraphs(prevBounds);
  167.                     AstarPath.active.UpdateGraphs(newBounds);
  168.                 }
  169.  
  170.     #if ASTARDEBUG
  171.                 Debug.DrawLine(prevBounds.min, prevBounds.max, Color.yellow);
  172.                 Debug.DrawLine(newBounds.min, newBounds.max, Color.red);
  173.     #endif
  174.                 prevBounds = newBounds;
  175.             }
  176.  
  177.             prevEnabled = colliderEnabled;
  178.             prevRotation = tr.rotation;
  179.  
  180.             // Set this here as well since the DoUpdateGraphs method can be called from other scripts
  181.             lastCheckTime = Time.realtimeSinceStartup;
  182.         }
  183.  
  184.         /** Volume of a Bounds object. X*Y*Z */
  185.         static float BoundsVolume (Bounds b) {
  186.             return System.Math.Abs(b.size.x * b.size.y * b.size.z);
  187.         }
  188.     }
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement