108 lines
4.4 KiB
C#
108 lines
4.4 KiB
C#
// Applies HistoryBounds to the physics world by projecting to a trigger Collider.
|
|
// This way we can use Physics.Raycast on it.
|
|
using UnityEngine;
|
|
|
|
namespace Mirror
|
|
{
|
|
public class HistoryCollider : MonoBehaviour
|
|
{
|
|
[Header("Components")]
|
|
[Tooltip("The object's actual collider. We need to know where it is, and how large it is.")]
|
|
public Collider actualCollider;
|
|
|
|
[Tooltip("The helper collider that the history bounds are projected onto.\nNeeds to be added to a child GameObject to counter-rotate an axis aligned Bounding Box onto it.\nThis is only used by this component.")]
|
|
public BoxCollider boundsCollider;
|
|
|
|
[Header("History")]
|
|
[Tooltip("Keep this many past bounds in the buffer. The larger this is, the further we can raycast into the past.\nMaximum time := historyAmount * captureInterval")]
|
|
public int boundsLimit = 8;
|
|
|
|
[Tooltip("Gather N bounds at a time into a bucket for faster encapsulation. A factor of 2 will be twice as fast, etc.")]
|
|
public int boundsPerBucket = 2;
|
|
|
|
[Tooltip("Capture bounds every 'captureInterval' seconds. Larger values will require fewer computations, but may not capture every small move.")]
|
|
public float captureInterval = 0.100f; // 100 ms
|
|
double lastCaptureTime = 0;
|
|
|
|
[Header("Debug")]
|
|
public Color historyColor = new Color(1.0f, 0.5f, 0.0f, 1.0f);
|
|
public Color currentColor = Color.red;
|
|
|
|
protected HistoryBounds history = null;
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
history = new HistoryBounds(boundsLimit, boundsPerBucket);
|
|
|
|
// ensure colliders were set.
|
|
// bounds collider should always be a trigger.
|
|
if (actualCollider == null) Debug.LogError("HistoryCollider: actualCollider was not set.");
|
|
if (boundsCollider == null) Debug.LogError("HistoryCollider: boundsCollider was not set.");
|
|
if (boundsCollider.transform.parent != transform) Debug.LogError("HistoryCollider: boundsCollider must be a child of this GameObject.");
|
|
if (!boundsCollider.isTrigger) Debug.LogError("HistoryCollider: boundsCollider must be a trigger.");
|
|
}
|
|
|
|
// capturing and projecting onto colliders should use physics update
|
|
protected virtual void FixedUpdate()
|
|
{
|
|
// capture current bounds every interval
|
|
if (NetworkTime.localTime >= lastCaptureTime + captureInterval)
|
|
{
|
|
lastCaptureTime = NetworkTime.localTime;
|
|
CaptureBounds();
|
|
}
|
|
|
|
// project bounds onto helper collider
|
|
ProjectBounds();
|
|
}
|
|
|
|
protected virtual void CaptureBounds()
|
|
{
|
|
// grab current collider bounds
|
|
// this is in world space coordinates, and axis aligned
|
|
// TODO double check
|
|
Bounds bounds = actualCollider.bounds;
|
|
|
|
// insert into history
|
|
history.Insert(bounds);
|
|
}
|
|
|
|
protected virtual void ProjectBounds()
|
|
{
|
|
// grab total collider encapsulating all of history
|
|
Bounds total = history.total;
|
|
|
|
// don't assign empty bounds, this will throw a Unity warning
|
|
if (history.boundsCount == 0) return;
|
|
|
|
// scale projection doesn't work yet.
|
|
// for now, don't allow scale changes.
|
|
if (transform.lossyScale != Vector3.one)
|
|
{
|
|
Debug.LogWarning($"HistoryCollider: {name}'s transform global scale must be (1,1,1).");
|
|
return;
|
|
}
|
|
|
|
// counter rotate the child collider against the gameobject's rotation.
|
|
// we need this to always be axis aligned.
|
|
boundsCollider.transform.localRotation = Quaternion.Inverse(transform.rotation);
|
|
|
|
// project world space bounds to collider's local space
|
|
boundsCollider.center = boundsCollider.transform.InverseTransformPoint(total.center);
|
|
boundsCollider.size = total.size; // TODO projection?
|
|
}
|
|
|
|
// TODO runtime drawing for debugging?
|
|
protected virtual void OnDrawGizmos()
|
|
{
|
|
// draw total bounds
|
|
Gizmos.color = historyColor;
|
|
Gizmos.DrawWireCube(history.total.center, history.total.size);
|
|
|
|
// draw current bounds
|
|
Gizmos.color = currentColor;
|
|
Gizmos.DrawWireCube(actualCollider.bounds.center, actualCollider.bounds.size);
|
|
}
|
|
}
|
|
}
|