using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Lightbug.Utilities { /// /// An implementation of a ColliderComponent for 3D colliders. /// public abstract class ColliderComponent3D : ColliderComponent { protected Collider Collider = null; public RaycastHit[] UnfilteredHits { get; protected set; } = new RaycastHit[20]; public List FilteredHits { get; protected set; } = new List(10); public Collider[] UnfilteredOverlaps { get; protected set; } = new Collider[20]; public List FilteredOverlaps { get; protected set; } = new List(10); #if UNITY_6000_0_OR_NEWER public PhysicsMaterial Material { get => Collider.sharedMaterial; set => Collider.sharedMaterial = value; } #else public PhysicMaterial Material { get => Collider.sharedMaterial; set => Collider.sharedMaterial = value; } #endif protected abstract int InternalOverlapBody(Vector3 position, Quaternion rotation, Collider[] unfilteredResults, List filteredResults, OverlapFilterDelegate3D filter); public sealed override int OverlapBody(Vector3 position, Quaternion rotation) { return InternalOverlapBody(position, rotation, UnfilteredOverlaps, FilteredOverlaps, null); } public override bool ComputePenetration(ref Vector3 position, ref Quaternion rotation, PenetrationDelegate Action) { return ComputePenetrationVector(ref position, ref rotation, Action) != Vector3.zero; } public override Vector3 ComputePenetrationVector(ref Vector3 position, ref Quaternion rotation, PenetrationDelegate Action) { int overlaps = OverlapBody(position, rotation); if (overlaps == 0) return Vector3.zero; Vector3 penetration = Vector3.zero; for (int i = 0; i < overlaps; i++) { var otherCollider = FilteredOverlaps[i]; if (otherCollider.transform.IsChildOf(Collider.transform)) continue; if (otherCollider.isTrigger) continue; var overlapped = Physics.ComputePenetration( Collider, position, rotation, otherCollider, otherCollider.transform.position, otherCollider.transform.rotation, out Vector3 direction, out float distance ); if (!overlapped) continue; penetration += direction * distance; Action?.Invoke(ref position, ref rotation, otherCollider.transform, direction, distance); } return penetration; } protected bool InternalHitFilter(RaycastHit raycastHit) { if (raycastHit.collider == Collider) return false; if (raycastHit.collider.isTrigger) return false; return true; } protected bool InternalOverlapFilter(Collider collider) { if (collider == this.Collider) return false; if (collider.isTrigger) return false; return true; } protected int FilterValidOverlaps(int hits, Collider[] unfilteredOverlaps, List filteredOverlaps, OverlapFilterDelegate3D Filter) { filteredOverlaps.Clear(); for (int i = 0; i < hits; i++) { Collider collider = unfilteredOverlaps[i]; // User-defined filter if (Filter != null) { bool validHit = Filter(collider); if (!validHit) continue; } filteredOverlaps.Add(collider); } return filteredOverlaps.Count; } protected override void Awake() { base.Awake(); #if UNITY_6000_0_OR_NEWER PhysicsMaterial material = new PhysicsMaterial("Frictionless 3D"); material.frictionCombine = PhysicsMaterialCombine.Minimum; material.bounceCombine = PhysicsMaterialCombine.Minimum; #else PhysicMaterial material = new PhysicMaterial("Frictionless 3D"); material.frictionCombine = PhysicMaterialCombine.Minimum; material.bounceCombine = PhysicMaterialCombine.Minimum; #endif material.dynamicFriction = 0f; material.staticFriction = 0f; material.bounciness = 0f; Collider.sharedMaterial = material; Collider.hideFlags = HideFlags.NotEditable; } protected override void OnEnable() { Collider.enabled = true; } protected override void OnDisable() { Collider.enabled = false; } } }