using System;
using System.Collections;
using ModV1.Source;
using Pathfinding;
using UnityEngine;
// KevinJ: Game specific faster version
// There are thousands of structural objects, it's not worthwhile to call Update() on all of them considering they don't move most of the time
// Disable Update() unless taking damage
// This is per-collider
public class DynamicGridObstacle2 : GraphModifier
{
Rigidbody rb;
DamageUnityEvents damageUnitEvents;
/// Collider to get bounds information from
Collider coll;
/// 2D Collider to get bounds information from
Collider2D coll2D;
/// Cached transform component
Transform tr;
/// The minimum change in world units along one of the axis of the bounding box of the collider to trigger a graph update
public float updateErrorPosition = 1;
// Rotational error, in degrees, to trigger a graph update
//public float updateErrorRotation = 30;
///
/// Time in seconds between bounding box checks.
/// If AstarPath.batchGraphUpdates is enabled, it is not beneficial to have a checkTime much lower
/// than AstarPath.graphUpdateBatchingInterval because that will just add extra unnecessary graph updates.
///
/// In real time seconds (based on Time.realtimeSinceStartup).
///
//public float checkTime = 0.2F;
/// Bounds of the collider the last time the graphs were updated
Bounds prevBounds;
/// Rotation of the collider the last time the graphs were updated
//Quaternion prevRotation;
/// True if the collider was enabled last time the graphs were updated
//bool prevEnabled;
//float lastCheckTime = -9999;
Bounds bounds
{
get
{
if (coll != null)
{
return coll.bounds;
}
else
{
var b = coll2D.bounds;
// Make sure the bounding box stretches close to infinitely along the Z axis (which is the axis perpendicular to the 2D plane).
// We don't want any change along the Z axis to make a difference.
b.extents += new Vector3(0, 0, 10000);
return b;
}
}
}
bool colliderEnabled
{
get
{
return coll != null ? coll.enabled : coll2D.enabled;
}
}
protected override void Awake()
{
base.Awake();
tr = transform;
//prevRotation = tr.rotation;
/*
// Make sure we update the graph as soon as we find that the collider is enabled
// prevEnabled = false;
if (AStarPathValid())
enabled = true;
else
enabled = false;
*/
Setup();
//DoUpdateGraphs2();
}
// KevinJ: Move GetCollider to Start()
protected virtual void Start()
{
rb = GetComponentInParent();
damageUnitEvents = GetComponentInParent();
if (damageUnitEvents == null)
{
enabled = false;
return;
}
damageUnitEvents.onMajorHealthDamage.AddListener(OnDamage);
damageUnitEvents.onMinorHealthDamage.AddListener(OnDamage);
// DoUpdateGraphs2();
//DoUpdateGraphs();
}
protected override void OnEnable()
{
base.OnEnable();
Setup();
DoUpdateGraphs();
}
///
/// Revert graphs when disabled.
/// When the DynamicObstacle is disabled or destroyed, a last graph update should be done to revert nodes to their original state
///
protected override void OnDisable()
{
base.OnDisable();
//OnDisableOrDestroy();
DoUpdateGraphs();
}
// KevinJ:
protected override void OnDestroy()
{
base.OnDestroy();
// if (enabled == false)
// OnDisableOrDestroy();
}
// KevinJ:
// protected void OnDisableOrDestroy()
// {
// DoUpdateGraphs2();
// }
private void OnDamage(GameObject arg0, Vector3 arg1, Vector3 arg2)
{
// if (AStarPathValid())
// enabled = true;
//DoUpdateGraphs2();
if (gameObject.activeInHierarchy)
StartCoroutine(DoUpgradeGraphsWhileMoving());
}
private void OnCollisionEnter(Collision collision)
{
// if (AStarPathValid())
// enabled = true;
//DoUpdateGraphs2();
if (gameObject.activeInHierarchy)
StartCoroutine(DoUpgradeGraphsWhileMoving());
}
// KevinJ: Move GetCollider to Start()
protected void Setup()
{
coll = GetComponent();
coll2D = GetComponent();
if (coll == null && coll2D == null)
{
return;
}
prevBounds = bounds;
}
public override void OnPostScan()
{
if (coll == null && coll2D == null)
return;
// In case the object was in the scene from the start and the graphs
// were scanned then we ignore the first update since it is unnecessary.
//prevEnabled = colliderEnabled;
// if (colliderEnabled)
// enabled = false;
prevBounds = bounds;
}
bool AStarPathValid()
{
if (AstarPath.active == null ||
AstarPath.active.gameObject.activeInHierarchy == false ||
AstarPath.active.isScanning ||
AstarPath.active.graphs.Length == 0 ||
AstarPath.active.graphs[0].active == false ||
//Time.realtimeSinceStartup - lastCheckTime < checkTime ||
!Application.isPlaying)
return false;
return true;
}
/*
protected virtual void Update()
{
if (coll == null && coll2D == null)
{
enabled = false;
return;
}
if (rb != null &&
(rb.isKinematic || rb.IsSleeping()))
{
// There are thousands of structural objects, it's not worthwhile to call Update() on all of them considering they don't move most of the time
// Not calling Update() is important even if the result is wrong and valid paths are blocked
enabled = false;
return;
}
if (AStarPathValid() == false)
{
return;
}
if (transform.position.y < 0.0f)
{
enabled = false;
return;
}
lastCheckTime = Time.realtimeSinceStartup;
if (colliderEnabled)
{
// The current bounds of the collider
Bounds newBounds = bounds;
var newRotation = tr.rotation;
Vector3 minDiff = prevBounds.min - newBounds.min;
Vector3 maxDiff = prevBounds.max - newBounds.max;
var extents = newBounds.extents.magnitude;
// This is the distance that a point furthest out on the bounding box
// would have moved due to the changed rotation of the object
//var errorFromRotation = extents * Quaternion.Angle(prevRotation, newRotation); // * Mathf.Deg2Rad;
// if (!prevEnabled)
// {
// DoUpdateGraphs();
// enabled = false;
// }
// If the difference between the previous bounds and the new bounds is greater than some value, update the graphs
//else
if (minDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition || maxDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition)
{
// Update the graphs as soon as possible
DoUpdateGraphs();
//enabled = false;
}
}
// else
// {
// // Collider has just been disabled
// if (prevEnabled)
// {
// DoUpdateGraphs();
// }
// enabled = false;
// }
}
*/
/*
void DoUpdateGraphs2()
{
if (AStarPathValid())
{
//lastCheckTime = Time.realtimeSinceStartup;
if (colliderEnabled)
{
// The current bounds of the collider
Bounds newBounds = bounds;
var newRotation = tr.rotation;
Vector3 minDiff = prevBounds.min - newBounds.min;
Vector3 maxDiff = prevBounds.max - newBounds.max;
//var extents = newBounds.extents.magnitude;
// This is the distance that a point furthest out on the bounding box
// would have moved due to the changed rotation of the object
//var errorFromRotation = extents * Quaternion.Angle(prevRotation, newRotation); // * Mathf.Deg2Rad;
// if (!prevEnabled)
// {
// DoUpdateGraphs();
// enabled = false;
// }
// If the difference between the previous bounds and the new bounds is greater than some value, update the graphs
//else
if (minDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition || maxDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition)
{
// Update the graphs as soon as possible
DoUpdateGraphs();
//enabled = false;
}
}
else
{
DoUpdateGraphs();
}
}
}
*/
public IEnumerator DoUpgradeGraphsWhileMoving()
{
while (enabled && colliderEnabled && rb.isKinematic == false && rb.IsSleeping() == false)
{
/*
// The current bounds of the collider
Bounds newBounds = bounds;
var newRotation = tr.rotation;
Vector3 minDiff = prevBounds.min - newBounds.min;
Vector3 maxDiff = prevBounds.max - newBounds.max;
//var extents = newBounds.extents.magnitude;
// This is the distance that a point furthest out on the bounding box
// would have moved due to the changed rotation of the object
//var errorFromRotation = extents * Quaternion.Angle(prevRotation, newRotation); // * Mathf.Deg2Rad;
// if (!prevEnabled)
// {
// DoUpdateGraphs();
// enabled = false;
// }
// If the difference between the previous bounds and the new bounds is greater than some value, update the graphs
//else
if (minDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition || maxDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition)
{
// Update the graphs as soon as possible
DoUpdateGraphs();
//enabled = false;
}
*/
yield return null;
}
// The current bounds of the collider
Bounds newBounds = bounds;
var newRotation = tr.rotation;
Vector3 minDiff = prevBounds.min - newBounds.min;
Vector3 maxDiff = prevBounds.max - newBounds.max;
if (minDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition || maxDiff.sqrMagnitude > updateErrorPosition * updateErrorPosition)
DoUpdateGraphs();
}
///
/// Update the graphs around this object.
/// Note: The graphs will not be updated immediately since the pathfinding threads need to be paused first.
/// If you want to guarantee that the graphs have been updated then call AstarPath.active.FlushGraphUpdates()
/// after the call to this method.
///
public virtual void DoUpdateGraphs()
{
if (AStarPathValid() == false)
return;
if (coll == null && coll2D == null)
return;
if (!colliderEnabled)
{
// If the collider is not enabled, then col.bounds will empty
// so just update prevBounds
AstarPath.active.UpdateGraphs(prevBounds);
}
else
{
Bounds newBounds = bounds;
Bounds merged = newBounds;
merged.Encapsulate(prevBounds);
// Check what seems to be fastest, to update the union of prevBounds and newBounds in a single request
// or to update them separately, the smallest volume is usually the fastest
if (BoundsVolume(merged) < BoundsVolume(newBounds) + BoundsVolume(prevBounds))
{
// Send an update request to update the nodes inside the 'merged' volume
AstarPath.active.UpdateGraphs(merged);
}
else
{
// Send two update request to update the nodes inside the 'prevBounds' and 'newBounds' volumes
AstarPath.active.UpdateGraphs(prevBounds);
if (newBounds.extents != Vector3.zero)
AstarPath.active.UpdateGraphs(newBounds);
}
#if ASTARDEBUG
Debug.DrawLine(prevBounds.min, prevBounds.max, Color.yellow);
Debug.DrawLine(newBounds.min, newBounds.max, Color.red);
#endif
prevBounds = newBounds;
}
//prevEnabled = colliderEnabled;
//prevRotation = tr.rotation;
// Set this here as well since the DoUpdateGraphs method can be called from other scripts
//lastCheckTime = Time.realtimeSinceStartup;
}
/// Volume of a Bounds object. X*Y*Z
static float BoundsVolume(Bounds b)
{
return System.Math.Abs(b.size.x * b.size.y * b.size.z);
}
}