167 lines
5.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Lightbug.Utilities
{
/// <summary>
/// An implementation of a ColliderComponent for 3D colliders.
/// </summary>
public abstract class ColliderComponent3D : ColliderComponent
{
protected Collider Collider = null;
public RaycastHit[] UnfilteredHits { get; protected set; } = new RaycastHit[20];
public List<RaycastHit> FilteredHits { get; protected set; } = new List<RaycastHit>(10);
public Collider[] UnfilteredOverlaps { get; protected set; } = new Collider[20];
public List<Collider> FilteredOverlaps { get; protected set; } = new List<Collider>(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<Collider> 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<Collider> 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;
}
}
}