HistoryCollider.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Applies HistoryBounds to the physics world by projecting to a trigger Collider.
  2. // This way we can use Physics.Raycast on it.
  3. using UnityEngine;
  4. namespace Mirror
  5. {
  6. public class HistoryCollider : MonoBehaviour
  7. {
  8. [Header("Components")]
  9. [Tooltip("The object's actual collider. We need to know where it is, and how large it is.")]
  10. public Collider actualCollider;
  11. [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.")]
  12. public BoxCollider boundsCollider;
  13. [Header("History")]
  14. [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")]
  15. public int boundsLimit = 8;
  16. [Tooltip("Gather N bounds at a time into a bucket for faster encapsulation. A factor of 2 will be twice as fast, etc.")]
  17. public int boundsPerBucket = 2;
  18. [Tooltip("Capture bounds every 'captureInterval' seconds. Larger values will require fewer computations, but may not capture every small move.")]
  19. public float captureInterval = 0.100f; // 100 ms
  20. double lastCaptureTime = 0;
  21. [Header("Debug")]
  22. public Color historyColor = new Color(1.0f, 0.5f, 0.0f, 1.0f);
  23. public Color currentColor = Color.red;
  24. protected HistoryBounds history = null;
  25. protected virtual void Awake()
  26. {
  27. history = new HistoryBounds(boundsLimit, boundsPerBucket);
  28. // ensure colliders were set.
  29. // bounds collider should always be a trigger.
  30. if (actualCollider == null) Debug.LogError("HistoryCollider: actualCollider was not set.");
  31. if (boundsCollider == null) Debug.LogError("HistoryCollider: boundsCollider was not set.");
  32. if (boundsCollider.transform.parent != transform) Debug.LogError("HistoryCollider: boundsCollider must be a child of this GameObject.");
  33. if (!boundsCollider.isTrigger) Debug.LogError("HistoryCollider: boundsCollider must be a trigger.");
  34. }
  35. // capturing and projecting onto colliders should use physics update
  36. protected virtual void FixedUpdate()
  37. {
  38. // capture current bounds every interval
  39. if (NetworkTime.localTime >= lastCaptureTime + captureInterval)
  40. {
  41. lastCaptureTime = NetworkTime.localTime;
  42. CaptureBounds();
  43. }
  44. // project bounds onto helper collider
  45. ProjectBounds();
  46. }
  47. protected virtual void CaptureBounds()
  48. {
  49. // grab current collider bounds
  50. // this is in world space coordinates, and axis aligned
  51. // TODO double check
  52. Bounds bounds = actualCollider.bounds;
  53. // insert into history
  54. history.Insert(bounds);
  55. }
  56. protected virtual void ProjectBounds()
  57. {
  58. // grab total collider encapsulating all of history
  59. Bounds total = history.total;
  60. // don't assign empty bounds, this will throw a Unity warning
  61. if (history.boundsCount == 0) return;
  62. // scale projection doesn't work yet.
  63. // for now, don't allow scale changes.
  64. if (transform.lossyScale != Vector3.one)
  65. {
  66. Debug.LogWarning($"HistoryCollider: {name}'s transform global scale must be (1,1,1).");
  67. return;
  68. }
  69. // counter rotate the child collider against the gameobject's rotation.
  70. // we need this to always be axis aligned.
  71. boundsCollider.transform.localRotation = Quaternion.Inverse(transform.rotation);
  72. // project world space bounds to collider's local space
  73. boundsCollider.center = boundsCollider.transform.InverseTransformPoint(total.center);
  74. boundsCollider.size = total.size; // TODO projection?
  75. }
  76. // TODO runtime drawing for debugging?
  77. protected virtual void OnDrawGizmos()
  78. {
  79. // draw total bounds
  80. Gizmos.color = historyColor;
  81. Gizmos.DrawWireCube(history.total.center, history.total.size);
  82. // draw current bounds
  83. Gizmos.color = currentColor;
  84. Gizmos.DrawWireCube(actualCollider.bounds.center, actualCollider.bounds.size);
  85. }
  86. }
  87. }